使用动态元素创建XML类

问题描述

我有一个要创建一个类的要求,该类可以使用动态数量的元素对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;
    }
}