2

I have 2 XML Files and I want to get all the XNodes , which are in both files, only based on their same Attribute "id". This is how an XML File looks like:

<parameters>
  <item id="57">
    <länge>8</länge>
    <wert>0</wert>
  </item>
  <item id="4">
    <länge>8</länge>
    <wert>0</wert>
  </item>
  <item id="60">
    <länge>8</länge>
    <wert>0</wert>
  </item>
</parameters>

Given a second XML File which looks like this:

<parameters>
  <item id="57">
    <länge>16</länge>
    <wert>10</wert>
  </item>
  <item id="144">
    <länge>16</länge>
    <wert>10</wert>
  </item>
</parameters>

Now I only want the XNode with the ID=57, since it is available in both files. So the output should look like this:

<item id="57">
    <länge>8</länge>
    <wert>0</wert>
</item>

I already did intersect both files like this:

aDoc = XDocument.Load(file);
bDoc = XDocument.Load(tmpFile);

intersectionOfFiles = aDoc.Descendants("item")
                        .Cast<XNode>()
                        .Intersect(bDoc.Descendants("item")
                        .Cast<XNode>(), new XNodeEqualityComparer());

This only seems to work, when all the descendant Nodes are the same. If some value is different, it won't work. But I need to get this to work on the same Attributes, the values or the descendants doesn't matter.

I also tried to get to the Attributes and intersect them, but this didn't work either:

intersectionOfFiles = tmpDoc
                        .Descendants(XName.Get("item"))
                        .Attributes()
                        .ToList()
                        .Intersect(fileDoc.Descendants(XName.Get("item")).Attributes()).ToList();

Am I missing something or is this a completely wrong approach?

Thanks in advance.

kevin
  • 71
  • 1
  • 8

1 Answers1

3

You should create your own IEqualityComparer that compares XML attributes you want:

public class EqualityComparerItem : IEqualityComparer<XElement>
{
    public bool Equals(XElement x, XElement y)
    {
        return x.Attribute("id").Value == y.Attribute("id").Value;
    }

    public int GetHashCode(XElement obj)
    {
        return obj.Attribute("id").Value.GetHashCode();
    }
}

which you would then pass to XML parsing code:

    var intersectionOfFiles = aDoc.Root
        .Elements("item")
        .Intersect(
            bDoc.Root
            .Elements("item"), new EqualityComparerItem());

I also changed some parts of your XML parsing code (XElement instead of XNode since "item" is XML element and "id" is XML attribute).

Ivan Golović
  • 8,732
  • 3
  • 25
  • 31
  • That worked like a charm, i am impressed. Thousand thanks to you :) – kevin Sep 24 '20 at 09:23
  • 1
    No problem :) Here there is no error checking code, of course, if there would be some errors in XML data - e.g. "item" element missing attribute "id" - you would have to implement some checks in Equals and GetHashCode methods. – Ivan Golović Sep 24 '20 at 09:27