C# 使用XmlSerializer反序列化和序列化XML时保持排序
我有以下测试XML字符串:C# 使用XmlSerializer反序列化和序列化XML时保持排序,c#,xml,xml-serialization,xmlserializer,C#,Xml,Xml Serialization,Xmlserializer,我有以下测试XML字符串: <?xml version="1.0" encoding="UTF-8"?> <test id="myid"> <b>b1</b> <a>a2</a> <a>a1</a> <b>b2</b> </test> 但是我不知道在序列化时如何按顺序排序。基本上没有XmlSerializer不支持此功能。如果要使用该选项,您需要使用XDo
<?xml version="1.0" encoding="UTF-8"?>
<test id="myid">
<b>b1</b>
<a>a2</a>
<a>a1</a>
<b>b2</b>
</test>
但是我不知道在序列化时如何按顺序排序。基本上没有
XmlSerializer
不支持此功能。如果要使用该选项,您需要使用XDocument
或XmlDocument
或XmlReader
手动编写该选项,您可以使用XmlSerializer
通过使用单个集合多次捕获属性,每个所需的元素名称一次。由于使用单个集合反序列化两个元素,因此顺序将自动保留。但是,要使此工作正常,XmlSerializer
必须能够在重新序列化时确定正确的元素名称。有两种方法可以实现这一点,如中所述:
如果集合包含多态项,则可以使用构造函数将元素名称映射到具体的项类型。例如,如果有一系列元素可能是字符串或整数,如下所示:
<Things>
<string>Hello</string>
<int>999</int>
</Things>
工作
有关使用[xmlcoiceIdentifier]
将具有不同名称的元素序列反序列化为同一类型的c#对象的更多示例,请参见示例或。出于好奇,是否有理由要求XML按特定顺序排列?我认为,只有在将数据加载或反序列化回对象后,才会使用排序。@gmiley我正在开发一个Office VSTO加载项,该加载项允许您添加自己的功能区选项卡,其中包含XML中定义的UI元素。xml元素顺序表示功能区UI顺序(例如:Save Button-Close Button或Close Button-Save Button),如果仔细想想-Test
类不包含任何有关“原始”顺序的信息,因此,没有办法做到这一点。然后,您可以按照您的想法添加一个排序属性/元素,并对集合执行排序。忘记xml的顺序。@gmiley仅对a和b进行排序并不能使a之前有一个b元素(如我的示例中所示)。感谢您对同一属性的多个XmlElement属性的建议。我现在可以在属性中添加ElementName以映射到自定义类。
<?xml version="1.0" encoding="utf-16"?>
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="myid">
<a>a2</a>
<a>a1</a>
<b>b1</b>
<b>b2</b>
</test>
[XmlRoot(ElementName="a")]
public class A
{
[XmlAttribute(AttributeName="order")]
public string Order { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName="b")]
public class B
{
[XmlAttribute(AttributeName="order")]
public string Order { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName="test")]
public class Test
{
[XmlElement(ElementName="a")]
public List<A> A { get; set; }
[XmlElement(ElementName="b")]
public List<B> B { get; set; }
[XmlAttribute(AttributeName="id")]
public string Id { get; set; }
}
<Things>
<string>Hello</string>
<int>999</int>
</Things>
public class Things
{
[XmlElement(Type = typeof(string)),
XmlElement(Type = typeof(int))]
public List<object> StringsAndInts { get; set; }
}
public abstract class StringElementBase
{
[XmlText]
public string Text { get; set; }
public static implicit operator string(StringElementBase element)
{
return element == null ? null : element.Text;
}
}
public sealed class A : StringElementBase
{
}
public sealed class B : StringElementBase
{
}
[XmlRoot(ElementName = "test")]
public class Test
{
[XmlElement("a", Type = typeof(A))]
[XmlElement("b", Type = typeof(B))]
public List<StringElementBase> Items { get; } = new List<StringElementBase>();
[XmlIgnore]
// For convenience, enumerate through the string values of the items.
public IEnumerable<string> ItemValues { get { return Items.Select(i => (string)i); } }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}