我正在使用XmlSerializer反序列化来自远程API的XML响应。有许多标准的预定义类,我已经为这些类建立了类。响应的关键部分如下所示:
<data>
<employee>
<name>John Doe</name>
<id>E1</id>
....
</employee>
<employee>
....
</employee>
....
</data>
或
<data>
<customer>
<name>Yoyodyne Systems</name>
<id>C1</id>
....
</customer>
<customer>
....
</customer>
....
</data>
所以我有Customer和Employee类,而Data类具有如下定义的属性:
[XmlElement("customer", typeof(Customer))]
public List<Customer> Customers { get; set; }
[XmlElement("employee", typeof(Employee))]
public List<Employee> Employees { get; set; }
每个结果中的数据元素仅包含一种类型的标记,而且我通常知道从给定请求中将返回哪种标记,因此我只访问该属性,而忽略其他留空的属性。
但是我想使其更具可扩展性。特别是远程应用程序中可能有不同的实例,其中包含自定义类,我不想将它们全部放入基本代码包中。我希望可以将一个属性添加到Data类中,例如
public List<object> ExtensionObjects { get; set; }
,然后使用XmlSerializer(Type, Type[])
构造函数提供要反序列化的实际类型。但是,我不知道如何告诉它将其应用于任何未知标签,甚至指定标签。例如,如果我有一个自定义Office类,如何使<office>...</office>
标记反序列化到其中?我有办法用XmlSerializer做到这一点,而不必一直回到将所有内容解析为XDocument吗?
编辑:
似乎有希望的一件事是试图处理OnUnknownElement事件。我可以为其创建一个委托,然后将其通过XmlDeserializationEvents对象传递给Deserialize方法调用。现在,我只需要找出将那些未知元素转换为扩展类实例的最佳方法。
答案 0 :(得分:0)
我已经确定了执行此操作的一种方法,尽管当然可能会有更好的方法。
如上所述,为OnUnknownElement设置处理程序:
XmlDeserializationEvents events = new XmlDeserializationEvents();
events.OnUnknownElement = delegate(object sender, XmlElementEventArgs args)
{
if (args.Element.Name == "office")
{
var data = (Data) args.ObjectBeingDeserialized;
var item = new Office(args.Element);
data.ExtensionObjects.Add(item);
}
};
var response = (Response) serializer.Deserialize(xmlReader, events);
然后,您所需要做的就是实现构造函数,以将XmlElement转换为对象。也许有一种更简洁的方法,但是考虑到这是一个简单的对象(只是“ name”和“ id”属性),我只是假设该元素只是命名元素的平面列表。
public Office(XmlElement e)
{
var valDict = e.ChildNodes.Cast<XmlNode>().Where(n => n is XmlElement)
.ToDictionary(x => x.Name, x => x.InnerText);
Name = valDict["name"];
Id = valDict["id"];
}
如果有更好的方法可以再次通过XmlSerializer,则无法找到它,因为我无法将XmlElement转换为XmlReader或Deserialize方法可以接受的任何其他功能。我想我可能可以再次将其序列化为文本,然后重新解析它,但这似乎很麻烦。