xsl-list
[Top] [All Lists]

Re: Is XSLT a suitable solution for generating a diff between versions of a document?

2005-05-08 19:38:46
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(_at_)onebox(_dot_)com 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(_at_)onebox(_dot_)com - email


--~------------------------------------------------------------------
XSL-List info and archive: 
http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to:
http://lists.mulberrytech.com/xsl-list/
or e-mail:
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--




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


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>
  • Re: Is XSLT a suitable solution for generating a diff between versions of a document?, Mukul Gandhi <=