我正在使用C#/ .NET反序列化类似于此的XML文件:
<?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>
对于反序列化的XML,我的类看起来像:
[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; }
}
反序列化时,我希望将Book元素的所有子节点(&lt; Thing1&gt;到&lt; ThingN&gt;)反序列化为Book的Things集合。但是,我无法弄清楚如何实现这一目标。现在,我无法将Thing节点存储在ThingElements集合中(通过XmlAnyElement)。
有没有办法将异构子节点反序列化为一个集合(非XmlElements)?
答案 0 :(得分:2)
如果您想将其序列化为一组简单的KeyValuePairs,则可以使用自定义Struct来完成此操作。不幸的是,内置的通用KeyValuePair不起作用。
但是,鉴于以下类定义:
[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;
}
}
当我使用这些信息序列化一个对象时,我得到一个看起来像这样的XML结构。
<?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>
我也能够成功地将XML读回到对象中并打印出信息。
您可以在控制台应用程序中自行测试,以查看结果。
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);
}
}
}
答案 1 :(得分:1)
我不确定我是否建议这样做,但确实有效......
XmlSerializer有一个“UnknownElement”事件,将为你的所有Thing1 ... ThingN元素调用它。您可以像这样处理此事件并反序列化您的事物:
serializer.UnknownElement += (obj, eargs) =>
{
var element = eargs.Element;
var book = eargs.ObjectBeingDeserialized as Book;
//Are we deserializing a book and do we have an unrecognized Thing element?
if (book != null && element.Name.StartsWith("Thing"))
{
//Deserialize our thing
using (var stringReader = new StringReader(element.OuterXml))
{
var thingSerializer = new XmlSerializer(typeof(Thing), new XmlRootAttribute(element.Name));
var thing = (Thing)thingSerializer.Deserialize(stringReader);
//Name can't be mapped for us, assign this manually
thing.Name = element.Name;
book.Things.Add(thing);
}
}
};
您显然需要更改“Thing”测试以适合您的实际数据。例如,您可能希望尝试将Book下的所有元素反序列化为“Thing”,在这种情况下,您将删除StartsWith条件。
您还需要使用XmlTextAttribute
标记Valuepublic class Thing
{
public string Name { get; set; }
[XmlTextAttribute]
public string Value { get; set; }
}