Dim xml = <Root>
<Parent id="1">
<Child>Thomas</Child>
</Parent>
<Parent id="2">
<Child>Tim</Child>
<Child>Jamie</Child>
</Parent>
</Root>
Dim parents = xml.Elements
In this case, children
includes all the Parent elements and all of the Child elements. What's the best way to grab only the direct descendants of <Root>
?
Should I write a LINQ query that selects elements where parent = <Root>
? Or is there some built-in method I'm missing that can get this for me?
EDIT: I had some confusion between XElement.Elements
and XElement.Descendants
. As Ruben Bartelink pointed out, XElement.Elements
will give me exactly what I was looking for.
Exec summary - you want:
xml.Elements.Select(function(element) new XElement(element.Name,element.Attributes))
First answer:
XElement.Descendants
, or is it a trick question ? :P There's an example of usage of Descendants here
Revised answer, thanks Tormod -- something did feel wrong!:
Elements gives direct descendants, as you're looking for. Descendants gives the full hierarchy [as you are alleging Elements does]. (The example I linked to makes this clear. Apologies for the confusion!
So, finally, what you're looking for is (this time in VB):
Dim xml = <Root>
<Parent id="1">
<Child>Thomas</Child>
</Parent>
<Parent id="2">
<Child>Tim</Child>
<Child>Jamie</Child>
</Parent>
</Root>
REM All nodes two levels down in the hierarchy
Dim level2Nodes = xml.Elements.SelectMany(function(element) element.Elements)
level2Nodes.Dump
REM All Child nodes, no matter where they are:
Dim children = xml.Descendants("Child")
Each of which will yield you the 3 ``` elements for different reasons as covered in the REMs.
(Paste the above directly into LINQPad in VB statement mode)
I now see what might be confusing you - when you use Elements and look at it in a visualiser, you are still seeing the children:-
Dim parents = xml.Elements
If you only want the actual names, you can use something like:
Dim parentNames = xml.Elements.Select(function(element) element.Name)
Note that in each of these cases, you are getting two results.
If you really want to strip out the chidren, you want:
Dim parentElements = xml.Elements.Select(function(element) new XElement(element.Name,element.Attributes))
Can you extend your question to show what you're really looking for?
XElement.Elements gets the collection of child elements. For example ...
var s = @"<root>
<e1>
<e2>
</e2>
</e1>
<e1>
<e2>
</e2>
</e1>
<e1>
<e2>
</e2>
</e1>
</root>";
var doc = XElement.Load( new StringReader(s) );
Console.WriteLine( doc.Elements().Count() ); // 3
Console.WriteLine( doc.Descendants().Count()); //6
Using Linq we can do that.
string s = "<Root><Parent id=\"1\"><Child>Thomas</Child></Parent><Parent id=\"2\"><Child>Tim</Child><Child>Jamie</Child></Parent></Root>";
XDocument xdoc = XDocument.Parse(s);
foreach (XElement DirectChild in xdoc.Descendants().Where(child => child.Parent == xdoc.Root))
{
//Do stuff here
}
Hope this helps. Thank you.
If all direct descendants have the same known element name, and this element name can't appear in another level, you can use xml.Descendants("Parent").
Why not use XPath?
Dim myXML As var = New XmlDocument()
myXML.Load(myXML.xml)
For Each node As XmlNode In myXML.SelectNodes("//")
Dim myVar As var = node.SelectSingleNode("Parent").InnerText
Next
Take this with a pinch of salt - I just converted it from C# to VB.