[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Is XSLT a suitable solution for generating a diff

Subject: Re: Is XSLT a suitable solution for generating a diff between versions of a document?
From: Mukul Gandhi <mukul_gandhi@xxxxxxxxx>
Date: Sun, 8 May 2005 19:38:46 -0700 (PDT)
xpath select count
Sometime back, I posted a stylesheet to test "two XML
documents for equality" .. Below is the stylesheet. It
just displays whether two XML documents are Equal or
Not Equal. It does not display what all and where the
differences are..

This stylesheet is not namespace aware. I think you
can take some help from this! There are also some
solutions listed at
http://www.dpawson.co.uk/xsl/sect2/N1777.html 

<?xml version="1.0"?> 
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
 
<xsl:output method="text" />  
 
<!-- parameter for "ignoring white-space only text
nodes" during comparison -->
<!-- if iws='y', "white-space only text nodes" will
not be considered during comparison  -->
<xsl:param name="iws" />
 
<xsl:variable name="doc1"
select="document('file1.xml')" />
<xsl:variable name="doc2"
select="document('file2.xml')" />
 
<xsl:template match="/">
 
    <!-- store hash of 1st document into a variable;
it is concatination of name and values of all nodes
-->
    <xsl:variable name="one">
      <xsl:for-each select="$doc1//@*">
        <xsl:sort select="name()" />
        <xsl:variable name="expr">
             <xsl:call-template
name="constructXPathExpr">
                 <xsl:with-param name="node"
select=".." />
                 <xsl:with-param name="xpath"
select="name(..)" />
             </xsl:call-template>
        </xsl:variable>
        <xsl:value-of
select="concat($expr,'/@',name(),':',.)"
/>:<xsl:value-of
select="count(../ancestor-or-self::node() |
../preceding::node())" /> 
      </xsl:for-each>
      <xsl:choose>
         <xsl:when test="$iws='y'">
           <xsl:for-each
select="$doc1//node()[not(normalize-space(self::text())
= '')]">
             <xsl:variable name="expr">
                 <xsl:call-template
name="constructXPathExpr">
                    <xsl:with-param name="node"
select="ancestor-or-self::*[1]" />
                    <xsl:with-param name="xpath"
select="name(ancestor-or-self::*[1])" />
                 </xsl:call-template>
             </xsl:variable>
             <xsl:value-of
select="concat($expr,'/',name(),':',.)"
/>:<xsl:value-of
select="count(ancestor-or-self::node() |
preceding::node())" />  
           </xsl:for-each>
         </xsl:when>
         <xsl:otherwise>
           <xsl:for-each select="$doc1//node()">
              <xsl:variable name="expr">
                  <xsl:call-template
name="constructXPathExpr">
                      <xsl:with-param name="node"
select="ancestor-or-self::*[1]" />
                      <xsl:with-param name="xpath"
select="name(ancestor-or-self::*[1])" />
                  </xsl:call-template>
             </xsl:variable>
             <xsl:value-of
select="concat($expr,'/',name(),':',.)"
/>:<xsl:value-of
select="count(ancestor-or-self::node() |
preceding::node())" />  
           </xsl:for-each>
         </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>  
    
    <!-- store hash of 2nd document into a variable;
it is concatination of name and values of all nodes
-->
    <xsl:variable name="two">
      <xsl:for-each select="$doc2//@*">
        <xsl:sort select="name()" />
        <xsl:variable name="expr">
            <xsl:call-template
name="constructXPathExpr">
                 <xsl:with-param name="node"
select=".." />
                 <xsl:with-param name="xpath"
select="name(..)" />
            </xsl:call-template>
         </xsl:variable>
         <xsl:value-of
select="concat($expr,'/@',name(),':',.)"
/>:<xsl:value-of
select="count(../ancestor-or-self::node() |
../preceding::node())" />  
      </xsl:for-each>
      <xsl:choose>
         <xsl:when test="$iws='y'">
           <xsl:for-each
select="$doc2//node()[not(normalize-space(self::text())
= '')]">
                 <xsl:variable name="expr">
                     <xsl:call-template
name="constructXPathExpr">
                         <xsl:with-param name="node"
select="ancestor-or-self::*[1]" />
                         <xsl:with-param name="xpath"
select="name(ancestor-or-self::*[1])" />
                    </xsl:call-template>
                 </xsl:variable>
                 <xsl:value-of
select="concat($expr,'/',name(),':',.)"
/>:<xsl:value-of
select="count(ancestor-or-self::node() |
preceding::node())" />  
           </xsl:for-each>
         </xsl:when>
         <xsl:otherwise>
           <xsl:for-each select="$doc2//node()">
                <xsl:variable name="expr">
                    <xsl:call-template
name="constructXPathExpr">
                        <xsl:with-param name="node"
select="ancestor-or-self::*[1]" />
                        <xsl:with-param name="xpath"
select="name(ancestor-or-self::*[1])" />
                    </xsl:call-template>
                </xsl:variable>
                <xsl:value-of
select="concat($expr,'/',name(),':',.)"
/>:<xsl:value-of
select="count(ancestor-or-self::node() |
preceding::node())" />  
           </xsl:for-each>
         </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>  
    <xsl:choose>
      <xsl:when test="$one = $two">
          Equal
      </xsl:when>
      <xsl:otherwise>
          Not equal        
      </xsl:otherwise>
    </xsl:choose>
</xsl:template>
 
<!-- a template to construct an XPath expression, for
a given element node -->
<xsl:template name="constructXPathExpr">
   <xsl:param name="node" />
   <xsl:param name="xpath" />
      
   <xsl:choose>       
     <xsl:when test="$node/parent::*">
       <xsl:call-template name="constructXPathExpr">
            <xsl:with-param name="node"
select="$node/parent::*" />
            <xsl:with-param name="xpath"
select="concat(name($node/parent::*),'/',$xpath)" />
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="concat('/',$xpath)" />
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

</xsl:stylesheet>

Also, XSLT may not be the suitable way to extract the
changes (in general to do software change management).
Probably, you must use an off-the-shelf tool like VSS
or "Clear Case" .. These tools give us robust set of
facility..

Regards,
Mukul

--- cknell@xxxxxxxxxx wrote:
> I have been considering a change management tool for
> comparing versions of an XML document. I have
> searched and haven't been able to find anything on
> point so I'm posting this question to the list.
> Given two versions of an XML document (say we are
> working with a document valid per a DTD or schema),
> is XSLT a suitable way of extracting the changes
> between versions of the document, and if so, can
> anyone show me a general method of writing a
> suitable stylesheet? Thanks.
> 
> -- 
> Charles Knell
> cknell@xxxxxxxxxx - email
> 
> 


		
Yahoo! Mail
Stay connected, organized, and protected. Take the tour:
http://tour.mail.yahoo.com/mailtour.html

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.