I have an xml document with main XElement "details" and several "detail" XElements, and for each detail Element i have also several "node" Element, this is a part of my xml document:
<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>
I am trying to transform this xml part to a list of object that contains just 3 properties correspond on "Key" and "value" elements. for example for each detail element in details and for each node element in detail i want to get just 3 nodes where the key element equals "PRODUCT NO" or "WIRE KIND(CODE)" or "CUT LENGTH"?
this is my code, it works, but i think it is not suitable for performance :
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 };
i think this is an example of select n+1 issue, because for each propety i must browse all nodes, how can i do the same with one loop ?
I would actually think about readability before performance, unless you know you have a performance issue. But even so, you can definitely improve the code. I would consider using ToDictionary
to convert each detail
element into a Dictionary<string, string>
, then you can get the bits you want:
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"] });
It's then very easy to add extra properties as you need them.