使用动态元素创建 XML 类

Posted

技术标签:

【中文标题】使用动态元素创建 XML 类【英文标题】:Create XML class with dynamic elements 【发布时间】:2020-12-15 07:14:27 【问题描述】:

我有一个要求,我想创建一个可以反序列化具有动态元素数量的 XML 的类。例如:

<root>
   <Element1>text</Element1>
   <Element2>text</Element2>
   <Element3>text</Element3>
   ....
   ...
   <Element10>text</Element10>
</root>

现在,在上面的 XML 中,前 3 个元素是强制性的,并且它们的元素名称是已知的。但在那之后我不知道 XML 有多少元素,这些元素的名称也不知道。

如何编写一个类以便我可以反序列化并读取它?

【问题讨论】:

或许这篇相关文章会对你有所帮助:(***.com/questions/13704752/…) @RyanWilson 谢谢。那真的很有帮助。我知道如何阅读 xml,但就我而言,我不知道 Elements 的名称。我不确定如何找到它。 最好的解决方案是更改创建如此糟糕 xml 的代码。 这是错误的 xml,因为动态创建的元素应该具有相同的名称并位于单独的节点内​​。 @HarshilDoshi 检查Heather D 在这篇文章 (***.com/questions/13171525/…) 上的答案,它不仅比我上面链接的更短更简单,而且它为使用 Expando Object 提供了指导而不是具体的类以及如何获取属性名称。 【参考方案1】:
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>

使用起来更容易。而且您可以轻松使用反序列化。

【讨论】:

不符合 OP 的要求。 “这不是一个糟糕的 xml。这是需求的本质。像这样动态生成 XML 也很常见。” @RyanWilson - 我展示的代码完全符合作者的要求。它正确解析作者的xml。 OP 非常清楚收到的xml 可能有任意数量的未知节点以及动态格式。仅当 OP 可以控制 xml 的构造时,这才满足要求,根据我对 cme​​ts 和帖子的解释,不确定它们是否可以。我并不是说您对 xml 格式的建议是错误的,但如果 OP 对它的格式没有任何发言权,这将无法解决问题。 我删除了反对票。请参阅我之前对这个答案的担忧的评论。 @RyanWilson - 我理解你。在我的信息的第一部分,我给出了答案,在第二部分 - 建议。【参考方案2】:

您可以创建通用匿名元素的列表。 它是通用的,因为您可能需要在序列化之前/反序列化之后的数据类型。 请注意,AnonymousElement 抽象类(不是通用类)的唯一目的是让您在不知道数据类型的情况下在 Root 类中创建列表,直到您在运行时调用 AddAnonymousElement。

如果您不需要通用行为,您可以删除抽象类并将派生的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;
    

【讨论】:

以上是关于使用动态元素创建 XML 类的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中动态创建 XML 模式?

jQuery循环遍历具有相同类的动态创建的元素

如何将动态创建的.xml文件与主AndroidManifest.xml合并

访问动态创建的元素的问题

如何使用 JAXB2 用动态元素编组 XML

如何使用 maven mvn test 命令行运行动态 testng.xml?