C#: Diff of two XML files - get only the nodes that have been modified/updated

946 Views Asked by At

I would like to get a list of nodes which have been modified (nodes added and nodes updated).

This is my program and XML files (before and after update)

fileBeforeUpdate.xml

<?xml version="1.0"?>
<DESCRIPTION>
    <DISTRIBUE_PAR>
      <UID>0000000000001</UID>
      <NOM>Anthony</NOM>
    </DISTRIBUE_PAR>
    <OBJET>Object Node</OBJET>
    <SUPPORT HREF="#PAPER"/>
    <NUMEROS_CHRONO>
      <CHRONO_1>aqwzsxedc-123456</CHRONO_1>
    </NUMEROS_CHRONO>
    <REFERENCE>reference</REFERENCE>
</DESCRIPTION>

fileAfterUpdate.xml

<?xml version="1.0"?>
<DESCRIPTION>
    <DISTRIBUE_PAR>
      <NOM>Antoni</NOM>
    </DISTRIBUE_PAR>
    <OBJET>Object Node</OBJET>
    <SUPPORT HREF="#MAIL"/>
    <NUMEROS_CHRONO>
      <CHRONO_1>aqwzsxedc-123456</CHRONO_1>
    </NUMEROS_CHRONO>
    <REFERENCE>reference</REFERENCE>
    <DATE>01/03/1994</DATE>
</DESCRIPTION>

Program.cs

var sb = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
    XmlDiff diff = new XmlDiff(XmlDiffOptions.IgnoreComments | XmlDiffOptions.IgnoreWhitespace | XmlDiffOptions.IgnoreNamespaces);
    diff.Compare(@"C:\fileBeforeUpdate", @"C:\fileAfterUpdate", true, xmlWriter);
    diff.Algorithm = XmlDiffAlgorithm.Precise;

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(sb.ToString());
 }

This is the StringBuilder output:

<xd:node match=\"1\">
    <xd:node match=\"1\">
        <xd:remove match=\"1\" />
        <xd:node match=\"2\">
            <xd:change match=\"1\">Antoni</xd:change>
        </xd:node>
    </xd:node>
    <xd:node match=\"3\">
        <xd:change match=\"@HREF\">#MAIL</xd:change>
    </xd:node>
    <xd:node match=\"5\" />
    <xd:add>
        <DATE>01/03/1994</DATE>
    </xd:add>
</xd:node>

For getting the list of nodes added, it's easily (in StringBuilder, I have node <xd:add> with node which added and values).

var addNodes = doc.GetElementsByTagName("xd:add");
var xmlNodesAdded = new StringBuilder();

foreach (XmlNode node in addNodes)
{
       xmlNodesAdded.Append(node.InnerXml);
       xmlNodesAdded.AppendLine();
}

However, to get the list of nodes (and attributes) which have been modified, it's more difficult...

How can I achieve this?
In StringBuilder, nodes xd:change do not specify the node which have been updated...

Thank you in advance.

1

There are 1 best solutions below

0
vipasane On

You can get HTML presentation of the changes by using XmlDiffView. (In some cases it wont recognize the change type correctly).

public string GetChangeHtml(string originalXML, string changedXML)
{
    XmlDiffView view = new XmlDiffView();
    var diffgram = Diff(originalXML, changedXML);
    string ret = "";
    using (StringReader legacySr = new StringReader(originalXML), diffGramSr = new StringReader(diffgram.ToString()))
    {
        using (XmlReader legacyReader = XmlReader.Create(legacySr), diffgramReader = XmlReader.Create(diffGramSr))
        {
            using (StringWriter sw = new StringWriter())
            {
                view.Load(legacyReader, diffgramReader);
                view.GetHtml(sw);
                ret = sw.ToString();
            }
        }
    }
    return ret;
}

Check the code in my question below: XMLDiff fails to recognize differences correcly?