选择一些特定的xml元素来列出匿名对象

时间:2014-12-15 16:13:03

标签: c# .net linq linq-to-xml xelement

我有一个带有主要XElement“详细信息”和几个“详细”XElements的xml文档,对于每个细节元素,我还有几个“节点”元素,这是我的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个属性,对应于“Key”和“value”元素。例如,对于每个细节元素的细节和每个节点元素的详细信息,我想得到3个节点,其中关键元素等于“PRODUCT NO”或“WIRE KIND(CODE)”或“CUT LENGTH”?

这是我的代码,它有效,但我认为它不适合性能:

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问题的一个例子,因为对于每个问题,我必须浏览所有节点,我怎么能用一个循环做同样的事情呢?

1 个答案:

答案 0 :(得分:2)

除非您知道性能问题,否则我会在性能之前考虑可读性。但即便如此,你绝对可以改进代码。我会考虑使用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"] });

然后非常可以根据需要添加额外的属性。