我有以下测试XML字符串:
<?xml version="1.0" encoding="UTF-8"?>
<test id="myid">
<b>b1</b>
<a>a2</a>
<a>a1</a>
<b>b2</b>
</test>
我使用这个类反序列化:
[XmlRoot(ElementName = "test")]
public class Test
{
[XmlElement(ElementName = "a")]
public List<string> A { get; set; }
[XmlElement(ElementName = "b")]
public List<string> B { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
如果我现在要序列化对象,结果将是:
<?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>
有没有办法保持初始排序顺序?
我想我不能使用[XmlElementAttribute(Order = x)]
因为订单不应该硬编码,但与初始xml完全相同。
我考虑过将订单属性添加到我的列表
[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; }
}
但序列化时我不知道如何订购。
答案 0 :(得分:1)
您可以使用XmlSerializer
执行此操作,方法是使用单个集合捕获<a>
和<b>
元素,并多次应用[XmlElement(Name, Type = typeof(...))]
属性,每个所需的元素名称。因为您使用单个集合来反序列化两个元素,所以会自动保留顺序。但是,要使其工作,XmlSerializer
必须能够在重新序列化时确定正确的元素名称。有两种方法可以实现这一点,如Choice Element Binding Support中所述:
如果集合包含多态项,则可以使用[XmlElementAttribute(String, Type)]
构造函数将元素名称映射到具体项类型。例如,如果你有一系列可能是字符串或整数的元素,那么:
<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; }
}
如果集合只包含单一类型的项,则元素名称可以在enum
值的关联数组中进行编码,其中enum
名称对应于元素名称和数组本身通过[XmlChoiceIdentifierAttribute]
属性识别。
有关详细信息,请参阅documentation examples。
我发现选项#1比选项#2更容易使用。使用此方法,以下模型将反序列化并重新序列化您的XML,同时成功保留<a>
和<b>
元素的顺序:
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; }
}
工作.Net fiddle。
有关使用[XmlChoiceIdentifier]
将具有不同名称的元素序列反序列化为相同类型的c#对象的更多示例,请参阅例如here或here。
答案 1 :(得分:-1)
不,基本上; XmlSerializer
不支持这一点。如果您要使用该选项,则需要使用XDocument
或XmlDocument
或XmlReader
手动编写。