/// Wednesday, April 5

Merging XML with XUpdate

I'm currently working on a backend process that receives two separate XML documents from different sources. The backend process must first transform each document, using XSLT, to conform to the company's standard format. The process then merges the two transformed documents into a single document. The merging operation requires some thought as the two documents share elements. Some elements are added while others are updated.

I wanted to automate this as much possible. The easy way out is to write some C# code and merge the documents using two XmlDocuments. But surely someone must have already thought of a better approach to this problem. My thought was to transform the first document like normal but transform the second document into an update document to be applied against the first document. The second document will contain embedded instructions on how to update the first.

After some googling, I found three solutions:

Microsoft XML Diff Language v.1.0 Beta

XUpdate Working Draft

Merging two XML Documents [using XSLT] by Oliver Becker

The Microsoft XML diff approach defines an XML diffgram language to describe the operations necessary to update a target document. It's not very readable using code numbers, etc for operations.

XUpdate follows a similiar approach defining basic commands and operations to update a target document. The language is much more readable and there exists several implementations for non-.NET languages. As a bonus I found a decent .NET implementation on Xinjie ZHANG's Homepage. The working draft, however, has not been touched for many years. I updated the DTD as well as the XUpdate class to support <xupdate:document-fragment/>.

Oliver Becker's approach is pure XSL. While I consider myself pretty darn good at XSL, XSL is just too much damn work. And trying to decipher someone else's XSL stylesheet takes at least three times the effort of trying to understand say C# code.

Here's an example using the XUpdate approach:

<!-- baseline.xml: target document -->
<recipes>
    <recipe name="unsalted bread" prep_time="5 mins" cook_time="3 hours">
        <title>Basic bread</title>
        <ingredient amount="3" unit="cups">Flour</ingredient>
        <ingredient amount="0.25" unit="ounce">Yeast</ingredient>
        <ingredient amount="1.5" unit="cups" state="warm">Water</ingredient>
        <instructions>
            <step>Mix all ingredients together, and knead thoroughly.</step>
            <step>Cover with a cloth, and leave for one hour in warm room.</step>
            <step>Knead again, place in a tin, and then bake in the oven.</step>
        </instructions>
    </recipe>
</recipes>
<!-- diffgram.xml: contains an append and update command -->
<xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate">
    <!-- append the Salt ingredient -->
    <xupdate:append select="/recipes/recipe[@name='unsalted bread']">
        <xupdate:document-fragment>
            <ingredient amount="1" unit="teaspoon">Salt</ingredient>
        </xupdate:document-fragment>
    </xupdate:append>

    <!-- change the recipe name to 'Salted Bread' -->
    <xupdate:update select="/recipes/recipe[@name='unsalted bread']/@name">Salted Bread</xupdate:update>
</xupdate:modifications>
// unit test
XmlDocument baseline = new XmlDocument();
baseline.Load(IOUtils.OpenEmbeddedResource("Xml/res/baseline.xml"));

XmlDocument diffgram = new XmlDocument();
diffgram.Load(IOUtils.OpenEmbeddedResource("Xml/res/diffgram.xml"));

XUpdate update = new XUpdate(baseline, diffgram);
update.Execute();

<!-- result of XUpdate.Execute() -->
<recipes>
    <recipe name="Salted Bread" prep_time="5 mins" cook_time="3 hours">
        <title>Basic bread</title>
        <ingredient amount="3" unit="cups">Flour</ingredient>
        <ingredient amount="0.25" unit="ounce">Yeast</ingredient>
        <ingredient amount="1.5" unit="cups" state="warm">Water</ingredient>
        <instructions>
            <step>Mix all ingredients together, and knead thoroughly.</step>
            <step>Cover with a cloth, and leave for one hour in warm room.</step>
            <step>Knead again, place in a tin, and then bake in the oven.</step>
        </instructions>
        <ingredient amount="1" unit="teaspoon">Salt</ingredient>
    </recipe>
</recipes>

Comments:

Hello,
thanks for this concise info! - I have one problem: Xinjie's homepage is gone - can you post the last version of his .net xupdate implementation? thanks
 
Sounds great. It would be nice if you could post the Xinjie's .net xupdate implementation
Thanks!
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?