20
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.

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Rob Sobers
  • 20,737
  • 24
  • 82
  • 111
  • Can you edit in the actual incantation you ended up using? BTW please download LINQPAd and try it - its great for testing stuff like this. See examples at http://www.dimecasts.net/Casts/ByTag/LinqPad – Ruben Bartelink Aug 04 '09 at 12:16

5 Answers5

20

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
Jose Luis
  • 3,307
  • 3
  • 36
  • 53
JP Alioto
  • 44,864
  • 6
  • 88
  • 112
18

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?

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • 3
    Descendants() method gets all descendants, not just direct descendants. In this case, descendants of "root" would include all Child elements as well. – Tormod Aug 04 '09 at 11:20
  • @Tormod, you sure? See the example? If not, whats the diff between Descendants and Elements? – Ruben Bartelink Aug 04 '09 at 11:34
4

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.

Mohamed Alikhan
  • 1,315
  • 11
  • 14
0

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").

Sharon
  • 83
  • 1
  • 9
-1

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.

Daniel May
  • 8,156
  • 1
  • 33
  • 43