Reputation: 23
I am using c sharp 5.0 and using LINQ to XML I try to programmatically get the differences between 2 xml files my first files is as simple as :
<?xml version="1.0" encoding="UTF-8" ?>
<table name="MYTABLE">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />
</columns>
</table>
and my second xml file is as simple as :
<?xml version="1.0" encoding="UTF-8" ?>
<table name=" MYTABLE ">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="NUMBER" />
</columns>
</table>
and my code is as simple as :
XDocument doc1 = XDocument.Load(@"Path\table1.xml");
XDocument doc2 = XDocument.Load(@"Path\table2.xml");
var cols1 = doc1.Descendants("column") ;
var cols2 = doc2.Descendants("column") ;
var itemsOnFirstFileOnly = cols1.Except(cols2);
var itemsOnSecondFileOnly = cols2.Except(cols1);
but to my surprise itemsOnFirstFileOnly returned ALL of columns that exist on table1.xml (not only MY_PARENT_ID & MY_CAPTION ) and itemsOnSecondFileOnly returned ALL of the columns that exist in table2.xml (not only MY_PARENT_ID),so why not Except doesn’t work as expected ??
Upvotes: 1
Views: 120
Reputation: 11238
You can also convert the XElement
s to strings, which takes attributes into account:
XDocument doc = XDocument.Parse(xml);
XDocument doc2 = XDocument.Parse(xml2);
var diffs = doc.Descendants().Select(e => e.ToString())
.Except(doc2.Descendants().Select(e => e.ToString()));
foreach (var e in diffs)
{
Console.WriteLine(e);
Console.WriteLine();
}
Considering columns, this returns only
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />
Upvotes: 0
Reputation: 4528
You can do this using Linq:
var itemsOnFirstFileOnly = cols1.Where(x => !cols2.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
var itemsOnSecondFileOnly = cols2.Where(x => !cols1.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
Basically in the above code:
name
attributesXElement
instances where the name is missing in the other collection.Upvotes: 0
Reputation: 37050
You have to implement Equals
on your Column
-class so that Except
knows when two Columns
are equal:
class Column
{
bool Equals(object other)
{
// ...
// skip further checks for simplicity
// ...
Column o = (Column) other;
return o.Name == this.Name && o.Type == this.Type ;
}
}
If you do not implement this method Except
will just check for reference-equality which can never be true because your columns come from differenct contexts (files in your case).
EDIT: As you are comparing XNodes
the thing is much easier because you can use the XNodeEqualityComparer
-class which has its own Equals
-implementation that exactly fit your needs as seen here. Thus the following should work:
var itemsOnFirstFileOnly = cols1.Except(cols2, new XNodeEqualityComparer());
Upvotes: 1