Reputation: 6292
I have the following xml file:
<?xml version="1.0" encoding="utf-8"?>
<nodes>
<node id="1">
<subnode name="a" value="1" />
<subnode name="b" value="2" />
</node>
<node id="2">
<subnode name="a" value="2" />
<subnode name="b" value="2" />
</node>
<node id="3">
<subnode name="a" value="1" />
<subnode name="b" value="1" />
</node>
<node id="4">
<subnode name="a" value="1" />
<subnode name="b" value="2" />
</node>
</nodes>
I need to select the id's of the nodes that have both a=1
and b=2
(in this case node 1 and node 4).
I would prefer to do it using linq, and I have the following code to select those that have a=1
. How do I expand the code to also take care of the second requirement?
var document = XDocument.Load(@"c:\temp\subnodes.xml");
var x = from topnode in document.Descendants("nodes")
let nodes = topnode.Descendants("node") from n in nodes
let subnodes = n.Descendants("subnode") from s in subnodes
where s.Attribute("name").Value == "a" && s.Attribute("value").Value == "1"
select n.Attribute("id").Value;
EDIT: I've made a .NET Fiddle here: https://dotnetfiddle.net/mOg3wv
Upvotes: 0
Views: 375
Reputation: 1675
UPDATE 2:
here's the LINQ based solution for this
var nodes = document.Descendants("nodes").Descendants("node");
return (from node in nodes
let aSubNode = node.Descendants("subnode")
.FirstOrDefault(a => a.Attribute("name")?.Value == "a" && a.Attribute("value")?.Value == "1")
let bSubNode = node.Descendants("subnode")
.FirstOrDefault(a => a.Attribute("name")?.Value == "b" && a.Attribute("value")?.Value == "2")
where aSubNode != null && bSubNode != null
select node.Attribute("id")?.Value).ToList();
UPDATE 1:
I updated the code to read id
attribute value from node
element instead of subnode
.
ORIGINAL:
following isn't all LINQ but this should solve your problem
var nodes = document.Descendants("nodes").Descendants("node");
var ids=new List<string>();
foreach (var node in nodes)
{
var aSubNode = node.Descendants("subnode")
.FirstOrDefault(a => a.Attribute("name")?.Value == "a" && a.Attribute("value")?.Value == "1");
var bSubNode=node.Descendants("subnode")
.FirstOrDefault(a => a.Attribute("name")?.Value == "b" && a.Attribute("value")?.Value == "2");
if (aSubNode==null || bSubNode==null)
continue;
ids.Add(node.Attribute("id")?.Value);
}
Upvotes: 1
Reputation: 18155
You can use following.
var result = document.Descendants("node").Where(x=>x.Descendants("subnode")
.All(c=>(c.Attribute("name").Value == "a" && c.Attribute("value").Value=="1") ||
(c.Attribute("name").Value == "b" && c.Attribute("value").Value=="2")))
.Select(x=>x.Attribute("id").Value);
Output
1
4
Upvotes: 1