I'm using C#/.NET to deserialize a XML file that looks akin to this:
<?xml version="1.0" encoding="utf-8" ?>
<Books>
<Book
Title="Animal Farm"
>
<Thing1>""</Thing1>
<Thing2>""</Thing2>
<Thing3>""</Thing3>
...
<ThingN>""</ThingN>
</Book>
... More Book nodes ...
</Books>
My classes, for the deserialized XML, look like:
[XmlRoot("Books")]
public class BookList
{
// Other code removed for compactness.
[XmlElement("Book")]
public List<Book> Books { get; set; }
}
public class Book
{
// Other code removed for compactness.
[XmlAttribute("Title")]
public string Title { get; set; }
[XmlAnyElement()]
public List<XmlElement> ThingElements { get; set; }
public List<Thing> Things { get; set; }
}
public class Thing
{
public string Name { get; set; }
public string Value { get; set; }
}
When deserializing, I want all the child nodes of the Book element (<Thing1> through <ThingN>) to be deserialized into a Book's Things collection. However, I'm unable to figure out how to accomplish that. Right now, I'm stuck storing the Thing nodes in the ThingElements collection (via XmlAnyElement).
Is there a way to deserialize heterogeneous child nodes into a collection (of non-XmlElements)?
The XmlSerializer enables you to control how objects are encoded into XML, it has a number of constructors. If you use any of the constructors other than the one that takes a type then a new temporary assembly is created EVERY TIME you create a serializer, rather than only once.
If you wanted to serialize this as a set of simple KeyValuePairs you could use a custom Struct to accomplish this. Unfortunately the built in generic KeyValuePair won't work.
But, given the following class definitions:
[XmlRoot("Books")]
public class BookList
{
[XmlElement("Book")]
public List<Book> Books { get; set; }
}
public class Book
{
[XmlAttribute("Title")]
public string Title { get; set; }
[XmlElement("Attribute")]
public List<AttributePair<String, String>> Attributes { get; set; }
}
[Serializable]
[XmlType(TypeName = "Attribute")]
public struct AttributePair<K, V>
{
public K Key { get; set; }
public V Value { get; set; }
public AttributePair(K key, V val)
: this()
{
Key = key;
Value = val;
}
}
When I serialize an object using this information I get an XML structure that looks something like this.
<?xml version="1.0"?>
<Books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Book Title="To win a woman">
<Attribute>
<Key>Author</Key>
<Value>Bob</Value>
</Attribute>
<Attribute>
<Key>Publish Date</Key>
<Value>1934</Value>
</Attribute>
<Attribute>
<Key>Genre</Key>
<Value>Romance</Value>
</Attribute>
</Book>
</Books>
I am also able to successfully read that XML right back into an object and print out the information.
You can test it out for yourself in a console application to see the results.
using(var file = File.OpenRead("booklist.xml"))
{
var readBookCollection = (BookList)serializer.Deserialize(file);
foreach (var book in readBookCollection.Books)
{
Console.WriteLine("Title: {0}", book.Title);
foreach (var attributePair in book.Attributes)
{
Console.CursorLeft = 3;
Console.WriteLine("Key: {0}, Value: {1}",
attributePair.Key,
attributePair.Value);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With