【发布时间】:2018-01-27 17:27:33
【问题描述】:
我想将一个 XML 文件反序列化为一个具有多个子类的类。 XML 如下所示:
<?xml version="1.0" encoding="utf-8"?>
<Objects>
<Group index="1">
<de>
<GroupName>ANTRIEB</GroupName>
</de>
<en>
<GroupName>missing translation!</GroupName>
</en>
<Level>2</Level>
</Group>
<Group index="2">
<de>
<GroupName>BREMSEN</GroupName>
</de>
<Level>3</Level>
</Group>
</Objects>
如果没有那些语言标签,将 XML 反序列化为类是没有问题的。当然,我可以为每个可能的语言标签创建一个属性。但是可能的语言列表应该是动态的(例如从配置文件中读取)。
这就是为什么我想将这些语言标签及其内容反序列化为字典,该字典使用语言作为键和内容的模型。
我的模型如下所示:
[XmlRoot("Objects")]
public class DeactivationsXml
{
[XmlElement("Group")]
public DeactivationsGroup[] Groups { get; set; }
}
[Serializable()]
public class DeactivationsGroup
{
[XmlIgnore]
public Dictionary<string, GroupName> GroupNames { get; set; } = new Dictionary<string, GroupName>();
public int Level { get; set; }
[XmlAttribute]
public byte index { get; set; }
}
public class GroupName
{
[XmlElement("GroupName")]
public string Name { get; set; }
}
我搜索了很长时间来解决这个问题,但找不到解决方案。我很确定,仅仅使用属性是不可能解决这个问题的。
是否存在一些混合方法,以便将 XML 文件的反序列化与无法自动反序列化的所有 XmlElement 的手动反序列化相结合?
对于我的问题,一个好的和可扩展的解决方案会很棒,因为 XML 结构很复杂(相同的问题多次出现不同的内容等)。 我无法更改 XML 的结构,所以请不要指出这一点。
方法
IXmlSerializable
我尝试在 DeactivationsGroup 类上实现 IXmlSerializable 接口,以便使用给定语言列表搜索具有这些名称的 XmlElements 并反序列化这些 XmlElements 的内容。
但这种方法行不通,因为您必须手动映射所有属性。
IExtensibleDataObject
该接口仅受 DataContractSerializer 支持。在最坏的情况下,如果没有找到其他解决方案,我可以在反序列化后使用此接口进行反序列化..
OnDeserialization
XmlSerializer 不支持此属性,但会提供我可能需要的功能。
XmlAnyElement
我想这是目前最好的选择。反序列化完成后是否存在一些回调以自动执行此操作?
可执行代码
这是到目前为止的全部代码。
public void Parse()
{
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
" <Objects>" +
" <Group index=\"1\">" +
" <de>" +
" <GroupName>ANTRIEB</GroupName>" +
" </de>" +
" <en>" +
" <GroupName>missing translation!</GroupName>" +
" </en>" +
" <Level>2</Level>" +
" </Group>" +
" <Group index=\"2\">" +
" <de>" +
" <GroupName>BREMSEN</GroupName>" +
" </de>" +
" <Level>3</Level>" +
" </Group>" +
" </Objects>";
XmlSerializer serializer = new XmlSerializer(typeof(DeactivationsXml));
using (TextReader fileStream = new StringReader(xml))
{
var result = (DeactivationsXml)serializer.Deserialize(fileStream);
}
}
[XmlRoot("Objects")]
public class DeactivationsXml
{
[XmlElement("Group")]
public DeactivationsGroup[] Groups { get; set; }
}
[Serializable()]
public class DeactivationsGroup
{
[XmlIgnore]
public Dictionary<string, GroupName> GroupNames { get; set; } = new Dictionary<string, GroupName>();
public int Level { get; set; }
[XmlAttribute]
public byte index { get; set; }
}
public class GroupName
{
[XmlElement("GroupName")]
public string Name { get; set; }
}
【问题讨论】:
-
你提前知道全套语言标签吗?如果这样做,您可以使用
[XmlChoiceIdentifier]执行此操作,如图所示,例如在this answer。或查看How to define multiple names for XmlElement field? 了解更多选项。 -
如果您事先不知道语言标签集,您可以在
[XmlAnyElement]代理属性中进行嵌套序列化,如How to deserialize xml elements that have different names, but the same set of attributes to a typed array/collection 所示。 -
您好 dbc,感谢您抽出宝贵时间。使用 XmlChoiceIdentifier 是不可能的,因为可能的语言在编译时是未知的(包含在配置文件中)。看起来 XmlAnyElemens 真的是我唯一的选择:|
标签: c# xml serialization xmlserializer