问题描述
我有一个要创建一个类的要求,该类可以使用动态数量的元素对XML进行反序列化。例如:
Argument is not sortable
1 2 3 5 6 1 7 2 5 3
^
sorting
stopped
here
现在,在上述XML中,前3个元素是必需的,并且它们的元素名称是已知的。但是之后,我不知道XML包含的元素数量,这些元素的名称也不知道。
如何编写一个类,以便我可以反序列化并阅读它?
解决方法
public class Root
{
// Mandatory elements
public string Element1 { get; set; }
public string Element2 { get; set; }
public string Element3 { get; set; }
// Dynamic elements
public List<string> Elements { get; set; }
}
我们可以使用linq2xml解析xml并使用数据填充类。
var xml = XElement.Load("test.xml");
Root root = new Root();
root.Element1 = xml.Element("Element1").Value;
root.Element2 = xml.Element("Element2").Value;
root.Element3 = xml.Element("Element3").Value;
xml.Element("Element1").Remove();
xml.Element("Element2").Remove();
xml.Element("Element3").Remove();
root.Elements = xml.Elements()
.Where(elem => elem.Name.LocalName.Contains("Element"))
.Select(elem => elem.Value)
.ToList();
Console.WriteLine(root.Element1);
Console.WriteLine(root.Element2);
Console.WriteLine(root.Element3);
foreach (var text in root.Elements)
{
Console.WriteLine(text);
}
最好的解决方案是更改创建此类xml的代码。例如,xml可能看起来像这样
<root>
<!-- Mandatory elements -->
<Element1>text1</Element1>
<Element2>text2</Element2>
<Element3>text3</Element3>
<!-- Dynamic elements -->
<Elements>
<Element>textA</Element>
<Element>textB</Element>
<Element>textC</Element>
</Elements>
</root>
使用起来要容易得多。而且您可以轻松地使用反序列化。
,您可以创建通用匿名元素的列表。
之所以通用,是因为您可能需要在序列化之前/反序列化之后的数据类型。
请注意,AnonymousElement
抽象类(不是通用类)的唯一目的是允许您在运行时调用AddAnonymousElement之前在不知道数据类型的情况下在Root类中创建列表。
如果您不需要通用行为,则可以删除抽象类并将派生的AnonymousElement
类更改为常规类。
[Serializable]
class Root
{
public string TagNameElement1 { get; set; }
public string TagNameElement2 { get; set; }
public string TagNameElement3 { get; set; }
public object ValueElement1 { get; set; }
public object ValueElement2 { get; set; }
public object ValueElement3 { get; set; }
public List<AnonymousElement> AnonymousElements = new List<AnonymousElement>();
public void AddAnonymousElement<T>(string tagname,T value)
{
AnonymousElement<T> elem = new AnonymousElement<T>(tagname,value);
AnonymousElements.Add(elem);
}
}
[Serializable]
public abstract class AnonymousElement
{
public string TagName { get; set; }
public AnonymousElement(string tagname)
{
this.TagName = tagname;
}
}
public class AnonymousElement<T>: AnonymousElement
{
public T Value { get; set; }
public AnonymousElement(string _TagName,T _Value):base(_TagName)
{
this.TagName = _TagName;
this.Value = _Value;
}
}