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

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

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

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

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

【问题讨论】:

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

标签: c# xml xml-parsing


【解决方案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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 2012-03-06
    相关资源
    最近更新 更多