Search code examples
c#linqelementdescendant

Using LINQ to exclude a Child Node from a collection of the same name


Per this XML, please note that BBB exists on two node levels.

<?xml version="1.0" encoding="utf-8"?>
<AAA>
  <BBB>
    <BBB>ONE</BBB>
    <CCC>1</CCC>
    <DDD>2</DDD>
    <EEE>3</EEE>
  </BBB>
  <BBB>
    <BBB>TWO</BBB>
    <CCC>4</CCC>
    <DDD>5</DDD>
    <EEE>6</EEE>
  </BBB>
  <BBB>
    <BBB>THREE</BBB>
    <CCC>7</CCC>
    <DDD>8</DDD>
    <EEE>9</EEE>
  </BBB>
</AAA>

I want to derive a collection of top level BBB's and extract them to their own file, with a file name based on the inner BBB.

My code is this:

XDocument xdoc = XDocument.Load(sourceFile);

var lv1s = from lv1 in xdoc.Descendants("AAA") select lv1;
var lv2s = from lv2 in xdoc.Descendants("BBB") select lv2;

foreach (var lv2 in lv2s)
{
  var name = lv2.Element("BBB").Value;
  lv2.Save(@"c:\temp\" + name + ".xml");
}

Problem is, LVL2 is picking up both the parent and descendants BBB. Can't seem to find a method that effectively filters out descendants.

For example I thought this was the key, but it yielded no results:

var lv2s = from lv2 in xdoc.Elements("BBB") select lv2;

Hoping you can provide me a ways to deal with the problem.

-------------------- EDIT --------------------

Okay I see what I did wrong. A typo.

LVL2 should have leveraged LVL1, like this:

var lv2s = from lv2 in lv1s.Elements("BBB") select lv2;   

That said, octavioccl's approach was much better than the bloated solution I came up with:

var parentBbbs =xdoc.Element("AAA").Elements("BBB");

Solution

  • You need to start getting the root element and then select the parent BBBs using Elements method:

    var parentBbbs =xdoc.Element("AAA").Elements("BBB");