使用动态元素创建 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
的构造时,这才满足要求,根据我对 cmets 和帖子的解释,不确定它们是否可以。我并不是说您对 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 类的主要内容,如果未能解决你的问题,请参考以下文章