views:

1433

answers:

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

Thanks!

+3  A: 

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 `<Child> 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 sue 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?

Ruben Bartelink
Descendants() method gets all descendants, not just direct descendants. In this case, descendants of "root" would include all Child elements as well.
Tormod
@Tormod, you sure? See the example? If not, whats the diff between Descendants and Elements?
Ruben Bartelink
@Tormod, mea culpa, editing!
Ruben Bartelink
A: 

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
XLinq does it quite neatly as is [once one gets over the confision of which method to use :P]
Ruben Bartelink
Fair enough :PI'll have to look into it, I guess XPath is becoming outdated if you're all moving on to XLinq!
Daniel May
A: 

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
+3  A: 

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
JP Alioto