我在将 XML 反序列化/序列化为 C# 对象时遇到问题。 XML 结构具有混合的元素顺序,并且我遇到了具有相同名称但不同用途的元素的问题。这是我的 C# 类的简化版本:
public class Uientry
{
[XmlElement(ElementName = "u")]
public string ID { get; set; }
[XmlElement(ElementName = "s")]
public List<string> Strings { get; set; }
[XmlElement(ElementName = "i")]
public List<string> Integer { get; set; }
[XmlElement(ElementName = "additional_data")]
public Additional_data Additional_data { get; set; }
}
当 XML 具有名称相同但用途不同的元素时,就会出现问题 并且它们的顺序不固定。例如,
<i>
元素(代表整数)可能出现在<s>
元素(代表字符串)之前和之后,从而导致冲突。
重要:我希望序列化后元素的顺序保持不变
这是我的一些xml代码
<uientry>
<u>606917248</u><!-- ID (80 d2 2c 24) -->
<s>root</s><!-- title -->
<s>CampaignRoot</s><!-- title2 -->
<i>0</i><!-- x offset -->
<i>0</i><!-- y offset -->
<no /><!-- uientry flag 1 -->
<yes /><!-- uientry flag 2 -->
<byte>1</byte><!-- uientry flag 3 -->
<no /><!-- uientry flag 4 -->
<no /><!-- uientry flag 5 -->
<no /><!-- uientry flag 6 -->
<no /><!-- uientry flag 7 -->
<yes /><!-- uientry flag 8 -->
<no /><!-- uientry flag 9 -->
<no /><!-- uientry flag 10 -->
<no /><!-- uientry flag 11 -->
<no /><!-- uientry flag 12 -->
<yes />
<unicode></unicode><!-- tooltip text -->
<unicode></unicode><!-- tooltip id -->
<i>0</i><!-- 00:00:00:00 --><!-- docking? -->
<i>0</i><!-- 00:00:00:00 --><!-- docking x? -->
<i>0</i><!-- 00:00:00:00 --><!-- docking y? -->
<no />
<i>0</i><!-- default state id -->
<images count="1">
<image>
<u>606535040</u><!-- ID (80 fd 26 24) -->
<s></s><!-- path -->
<i>1280</i><!-- x size -->
<i>960</i><!-- y size -->
<no />
</image>
</images>
<i>0</i><!-- 00:00:00:00 --><!-- mask image? -->
<i>0</i>
<states count="0">
</states>
<children count="0">
</children>
<additional_data type="none" />
</uientry>
如何修改我的 C# 类或使用属性来处理这种情况?有没有办法指示 XML 反序列化器考虑元素的用途并进行相应的处理?
感谢您的帮助:)
您的 XML 的架构包含一系列 choice 元素。选择元素指示一组固定元素(
<u>
、<i>
、<yes>
、<no>
、<unicode>
等)中的一个将出现在 XML 中。 XmlSerializer
支持选择元素,如选择元素绑定支持中所述:
如果各个选择元素的类型及其名称不同,Xsd.exe 仅将
属性应用于公共成员。如果它们仅在名称上有所不同,Xsd.exe 会另外应用XmlElementAttribute
,并添加额外的逻辑来进行选择。XmlChoiceIdentifierAttribute
因此,正如 Xml 反序列化 - 将两个元素合并到单个 List 对象中
UientryItem
,然后对于
<uientry>
中可能出现的每个元素,创建与该元素相对应的子类型,并通过XmlTypeAttribute.TypeName
属性指示名称:
public abstract class UientryItem;
[XmlType("u"), XmlRoot("u")]
public class UientryId : UientryItem
{
[XmlText] public string Value { get; set; }
}
[XmlType("s"), XmlRoot("s")]
public class UientryTitle : UientryItem
{
[XmlText] public string Value { get; set; }
}
[XmlType("no"), XmlRoot("no")]
public class UientryNo : UientryItem;
[XmlType("yes"), XmlRoot("yes")]
public class UientryYes : UientryItem;
[XmlType("byte"), XmlRoot("byte")]
public class UientryByte : UientryItem
{
[XmlText] public byte Value { get; set; }
}
[XmlType("unicode"), XmlRoot("unicode")]
public class UientryUnicode : UientryItem
{
[XmlText] public string Value { get; set; }
}
[XmlType("i"), XmlRoot("i")]
public class UientryInt : UientryItem
{
[XmlText] public int Value { get; set; }
}
[XmlType("images"), XmlRoot("images")]
public class UientryImages : UientryItem
{
[XmlAttribute("count")]
public int Count { get => Images?.Count?? 0; set { } }
[XmlElement("image")]
public List<UientryImage> Images { get; set; } = new();
}
[XmlType("image"), XmlRoot("image")]
public class UientryImage
{
[XmlElement(typeof(UientryId)),
XmlElement(typeof(UientryTitle)),
XmlElement(typeof(UientryNo)),
XmlElement(typeof(UientryYes)),
XmlElement(typeof(UientryByte)),
XmlElement(typeof(UientryUnicode)),
XmlElement(typeof(UientryInt)),
XmlElement(typeof(UientryImages)),
XmlElement(typeof(UientryStates)),
XmlElement(typeof(UientryChildren)),
XmlElement(typeof(UientryAdditionalData))]
public List<UientryItem> Items { get; set; } = new();
}
[XmlType("states"), XmlRoot("states")]
public class UientryStates : UientryItem
{
[XmlAttribute("count")] public int Count { get; set; }
// TODO: fill in appropriate properties
}
[XmlType("children"), XmlRoot("children")]
public class UientryChildren : UientryItem
{
[XmlAttribute("count")] public int Count { get; set; }
// TODO: fill in appropriate properties
}
[XmlType("additional_data"), XmlRoot("additional_data")]
public class UientryAdditionalData : UientryItem
{
[XmlAttribute("type")] public string Type { get; set; }
// TODO: fill in appropriate properties
}
接下来定义
Uientry
如下:
[XmlType("uientry"), XmlRoot("uientry")]
public class Uientry
{
[XmlElement(typeof(UientryId)),
XmlElement(typeof(UientryTitle)),
XmlElement(typeof(UientryNo)),
XmlElement(typeof(UientryYes)),
XmlElement(typeof(UientryByte)),
XmlElement(typeof(UientryUnicode)),
XmlElement(typeof(UientryInt)),
XmlElement(typeof(UientryImages)),
XmlElement(typeof(UientryStates)),
XmlElement(typeof(UientryChildren)),
XmlElement(typeof(UientryAdditionalData))]
public List<UientryItem> Items { get; set; } = new();
}
您将能够使用
<uientry>
反序列化您的
new XmlSerializer(typeof(Uientry))
,例如如下:using var textReader = new StringReader(xmlString);
var serializer = new XmlSerializer(typeof(Uientry));
var uiEntry = (Uientry)serializer.Deserialize(textReader);
演示小提琴在这里