选择一些特定的 XML 元素以列出匿名对象

本文关键字:对象 元素 XML 选择 | 更新日期: 2023-09-27 18:34:13

我有一个xml文档,其中包含主要的XElement"详细信息"和几个"详细信息"XElements,对于每个详细信息元素,我还有几个"节点"元素,这是我xml文档的一部分:

<details>
    <detail>
      <node>
        <key>HEADER ID</key>
        <value>D10</value>
      </node>
      <node>
        <key>PRODUCT NO</key>
        <value>9671834480D04  </value>
      </node>
      <node>
        <key>WIRE (CODE)</key>
        <value>AD8</value>
      </node>
      <node>
        <key>WIRE SIZE(CODE)</key>
        <value>047</value>
      </node>
      <node>
        <key>WIRE COLOR(CODE)</key>
        <value>30</value>
      </node>
      <node>
        <key>CUT LENGTH</key>
        <value>01910</value>
      </node>
    </detail>
    <detail>
      <node>
        ...
      </node>
        ...
    </detail>
        ...
<details>

我正在尝试将此 xml 部分转换为仅包含 3 个属性的对象列表,这些属性对应于"键"和"值"元素。 例如,对于每个细节元素的详细信息和每个节点元素的详细信息,我只想得到 3 个节点,其中关键元素等于"产品编号"或"电线种类(代码)"或"切割长度"?

这是我的代码,它可以工作,但我认为它不适合性能:

var champs = 
    from detail in details
    let productNo = detail.Elements("node")
        .Where(k => k.Element("key")
        .Value == "PRODUCT NO")
        .Select(v => v.Element("value").Value)
        .First()
    let wireCode = detail.Elements("node")
        .Where(k => k.Element("key").Value == "WIRE (CODE)")
        .Select(v => v.Element("value").Value)
        .First()
    let cutLength = detail.Elements("node")
        .Where(k => k.Element("key").Value == "CUT LENGTH")
        .Select(v => v.Element("value").Value)
        .First()
    select new { ProductNo = productNo, WireCode = wireCode , CutLength = cutLength };

我认为这是选择 N+1 问题的一个例子,因为对于每个属性,我必须浏览所有节点,我怎样才能用一个循环做同样的事情?

选择一些特定的 XML 元素以列出匿名对象

我实际上会在性能之前考虑可读性,除非您知道自己有性能问题。但即便如此,您绝对可以改进代码。我会考虑使用 ToDictionary 将每个detail元素转换为Dictionary<string, string>,然后您可以获得所需的位:

var query = details.Select(d => d.Elements("node")
                                 .ToDictionary(n => n.Element("key").Value,
                                               n => n.Element("value").Value))
                   .Select(x => new { ProductNo = x["PRODUCT NO"],
                                      WireCode = x["WIRE (CODE)"],
                                      CutLength = x["CUT LENGTH"] });

然后,您可以根据需要轻松添加额外的属性。