0

How can I iterate only through the common nodes between two documents?

Right now, I am able to iterate through all the nodes of my document:

var xmlBody = @"<?xml version="1.0" encoding="UTF-8"?>
<Visit>
   <Person>...</Person>
   <Name>...</Name>
   <Color>...</Color>
</Visit>";
    var xdoc = XDocument.Parse(xmlBody);
    foreach (XElement child in xdoc.Elements())
                {//do stuff}

I'd like to ONLY iterate through the common nodes between xdoc.Elements() and my nodeList:

var nodeList = new List<string> { "Name", "LastName", "Color" };

The intersection of the nodeList and the xdoc would be just these nodes: Name, Color:

How can I iterate against the intersection, something like this

foreach(XElement child in xdoc.Elements().Intersect(nodeList))
Alex Gordon
  • 57,446
  • 287
  • 670
  • 1,062
  • 2
    `xdoc.Elements().Where(e => nodeList.Contains(e.LocalName))` will filter based on the local name being in your list. – juharr Mar 05 '19 at 16:14
  • @juharr `xelement does not contain a definition for localname` https://photos.google.com/lr/photo/AHOXsYLU7wCrgaOisszJkRes3So0zXCDI3uItve4ojsFZk-XSYQz1k_9cBEJ1z19Ao7cBafY3PU7WiNg2MzU0lEvpYY8n6jBtA – Alex Gordon Mar 05 '19 at 16:24
  • @juharr Just keep in mind that this is a O(n²) solution, it won't work very well for big lists. – Alex Gordon Mar 05 '19 at 16:33
  • For a big list you should create a `HashSet` instead. And technically it's O(m*n) because the number of nodes isn't always equal to the number of names. – juharr Mar 05 '19 at 16:35
  • thank you, could you address the `xelement does not contain` issue? – Alex Gordon Mar 05 '19 at 16:37
  • It's actually `e.Name.LocalName`. – juharr Mar 05 '19 at 16:38

2 Answers2

2

Instead of a list you probably should use a HashSet then you can use the following Linq to filter out the nodes based on the local name

var nodeNames = new HashSet<string> { "Name", "LastName", "Color" };

foreach(var child in xdoc.Elements().Where(e => nodeNames.Contains(e.Name.LocalName)))
{
    // Your code here.
}
juharr
  • 31,741
  • 4
  • 58
  • 93
1

I would use Linq Where and Contains like this:

        var xmlBody = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<Visit>
   <Person>...</Person>
   <Name>...</Name>
   <Color>...</Color>
</Visit>";
        var xdoc = XDocument.Parse(xmlBody);
        var nodeList = new List<string> { "Name", "LastName", "Color" };

        var intersectedElements = xdoc.Elements()
            .First() //<Visit>
            .Elements()
            .Where(element => nodeList.Contains(element.Name.LocalName));

        foreach (XElement child in intersectedElements)
        {
            Console.WriteLine($"{child.Name.LocalName}: {child.Value}");
        }

If you want elements that could be nested deeper than use Descendants.

        var intersectedNestedElements = xdoc.Descendants()
            .Where(element => nodeList.Contains(element.Name.LocalName));

        foreach (XElement child in intersectedNestedElements)
        {
            Console.WriteLine($"{child.Name.LocalName}: {child.Value}");
        }

Both output:

Name: ...
Color: ...