Re: Merging XML

Subject: Re: Merging XML
From: Tom Mullen <Tom.Mullen@xxxxxxxxxxx>
Date: Fri, 04 Aug 2000 14:20:55 +0000 (GMT)
Josh,

using the examples you gave:

>1.xml:
>  <A>
>  <B name="123">
>     <C>
>      <D>
>       <E>val 1</E>
>      </D>
>     </C>
>     <G>1</G>
>  </B>
>  </A>
>2.xml:
>  <A>
>  <B name="123">
>    <H>
>      <F>
>         Val3
>      </F>
>    </H>
>    <C>
>      <D>
>       <E> Val2 </E>
>      </D>
>    </C>
>  </B>
>  </A>
>
>
>If I rearrange the order to put <A><B><C>.. instead of <A><B><H>..
>it works.
>


Then the following xsl doc treats both 2) and its rearranged form the same.
 A few warnings:

1) Anybody who knows anything about XSL will recognise this as being
written by a newbie. (any comments at all on it would be most welcome)
2) I think there needs to be some form of ignore whitespace setting (I get
that there is a difference in B when there isn't)
3) This xsl only works with the format of the XML documents above.  I think
a generic solution would be an order of magnitude more difficult (anybody 
prepared to take up the gauntlet?).
4) Only a difference html is produced, I haven't got round to installing
<xsl:copy> and/or <xsl:copy-of> at the appropriate points.  However, this
example should explain the approach a little more clearly.
5) Apologies in advance for the lack of comments


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">

<xsl:param name="oldfile" />

<xsl:variable name="old" select="document($oldfile)" />
<xsl:variable name="new" select="/" />


<xsl:template match="/A">
<html>
<head><title>Comparison</title></head>
<body>
<h1>Comparison</h1>
<xsl:comment><xsl:value-of select="$new/"/></xsl:comment>
<xsl:comment><xsl:value-of select="$old/"/></xsl:comment>
<xsl:comment><xsl:value-of select="$oldfile"/></xsl:comment>
<xsl:call-template name="compall">
    <xsl:with-param name="new" select="$new" />
    <xsl:with-param name="old" select="$old" />
</xsl:call-template>
</body>
</html>
</xsl:template>

<xsl:template name="compall">
  <xsl:param name="old" />
  <xsl:param name="new" />

  <xsl:variable name="oldval" select="$old/text()"/>
  <xsl:variable name="newval" select="$new/text()"/>
  <xsl:if test="not((string-length($oldval)=string-length($newval)) and
contains($oldval,$newval))">
    <xsl:comment>different vals</xsl:comment>
    <xsl:variable name="oldname" select="name($old)" />
    <xsl:variable name="newname" select="name($new)" />
    <p>Altered NEW:<xsl:value-of select="$newname"/>=<xsl:value-of
select="$newval"/></p>
    <p>Altered OLD:<xsl:value-of select="$oldname"/>=<xsl:value-of
select="$oldval"/></p>
  </xsl:if>

  <xsl:call-template name="list-additional">
    <xsl:with-param name="head">Added:</xsl:with-param>
    <xsl:with-param name="more" select="$new" />
    <xsl:with-param name="less" select="$old" />
  </xsl:call-template>

  <xsl:call-template name="list-additional">
    <xsl:with-param name="head">Removed:</xsl:with-param>
    <xsl:with-param name="more" select="$old" />
    <xsl:with-param name="less" select="$new" />
  </xsl:call-template>

  <xsl:call-template name="list-compare">
    <xsl:with-param name="old" select="$old" />
    <xsl:with-param name="new" select="$new" />
  </xsl:call-template>

</xsl:template>


<xsl:key name="logs" match="B" use="@name" />

<xsl:template name="list-additional">
  <xsl:param name="head" />
  <xsl:param name="more" />
  <xsl:param name="less" />
  <ul>
  <xsl:if test="$more/B">
  <xsl:for-each select="$more/B">
    <xsl:variable name="item" select="." />
    <!-- select the 'less' document so that the key indexes into that
         document -->
    <xsl:for-each select="$less">
    <xsl:if test="not(key('logs', $item/@name))">
        <xsl:comment><xsl:value-of select="$item"/></xsl:comment>
        <li><xsl:value-of select="$head"/><xsl:apply-templates
select="$item" mode="describe" /></li>
      </xsl:if>
    </xsl:for-each>
  </xsl:for-each>
  </xsl:if>
  <xsl:for-each select="$more/*"> 
    <xsl:variable name="item" select="." />
    <xsl:variable name="itemname" select="name(.)" />
    <xsl:choose>
      <xsl:when test="self::B"/>
      <xsl:otherwise>
 <xsl:comment>looking for <xsl:value-of select="$itemname"/></xsl:comment>
        <xsl:choose>
	  <xsl:when test="$less/*[name()=name($item)]"/>
          <xsl:otherwise>
            <xsl:comment><xsl:value-of select="$item"/></xsl:comment>
            <li><xsl:value-of select="$head"/><xsl:apply-templates
select="$item" mode="describe" /></li>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each>
  </ul>
</xsl:template>

<xsl:template name="list-compare">
  <xsl:param name="old" />
  <xsl:param name="new" />
 <xsl:variable name="oldname" select="name($old)" />
 <xsl:variable name="newname" select="name($new)" />
  <ul>
  <xsl:if test="$old/B">
  <xsl:for-each select="$old/B">
    <xsl:variable name="old2" select="." />
    <xsl:for-each select="$new">
      <xsl:if test="key('logs', $old2/@name)">
	<xsl:variable name="new2" select="key('logs', $old2/@name)"/>
          <xsl:call-template name="compall">
            <xsl:with-param name="new" select="$new2" />
            <xsl:with-param name="old" select="$old2" />
          </xsl:call-template>
      </xsl:if>
    </xsl:for-each>
  </xsl:for-each>
  </xsl:if>
  <xsl:for-each select="$old/*"> 
    <xsl:variable name="old2" select="." />
    <xsl:variable name="old2name" select="name(.)" />
    <xsl:choose>
      <xsl:when test="self::B"/>
      <xsl:otherwise>
 <xsl:comment>looking for <xsl:value-of select="$old2name"/></xsl:comment>
	<xsl:variable name="new2" select="$new/*[name()=$old2name]"/>
	<xsl:if test="$new/*[name()=name($old2)]">
	<xsl:variable name="newval" select="$new2/self::text()"/>
	<xsl:variable name="oldval" select="$old2/self::text()"/>
 	<xsl:comment>New val=<xsl:value-of select="$newval"/>Old
val=<xsl:value-of select="$oldval"/></xsl:comment>
        <xsl:call-template name="compall">
          <xsl:with-param name="new" select="$new2" />
          <xsl:with-param name="old" select="$old2" />
        </xsl:call-template>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each>
  </ul>
</xsl:template>

<xsl:template match="*" mode="describe">
  <xsl:value-of select="name()" /><xsl:text>=</xsl:text><xsl:value-of
select="text()" />
</xsl:template>

<xsl:template match="B" mode="describe">
   <xsl:text>B-</xsl:text><xsl:value-of select="@name" />
</xsl:template>

</xsl:stylesheet>



Thanks

Tom

-----------------------------------------------------------------
        Visit our Internet site at http://www.reuters.com

Any views expressed in this message are those of  the  individual
sender,  except  where  the sender specifically states them to be
the views of Reuters Ltd.


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread
  • Merging XML
    • Roshan Sharma - Thu, 03 Aug 2000 20:40:40 GMT
      • Tom Mullen - Fri, 04 Aug 2000 08:48:58 +0000 (GMT)
      • Tom Mullen - Fri, 04 Aug 2000 14:20:55 +0000 (GMT) <=
      • <Possible follow-ups>
      • Oliver Becker - Mon, 7 Aug 2000 10:08:06 +0200 (MET DST)
        • Tom Mullen - Tue, 08 Aug 2000 13:09:59 +0000 (GMT)
      • Oliver Becker - Tue, 8 Aug 2000 19:30:19 +0200 (MET DST)