Re: [xsl] Comparing direct ancestors

Subject: Re: [xsl] Comparing direct ancestors
From: Ihe Onwuka <ihe.onwuka@xxxxxxxxxxxxxx>
Date: Mon, 28 May 2012 21:49:26 +0100
On Mon, May 28, 2012 at 7:27 PM, Spencer Tickner
<spencertickner@xxxxxxxxx> wrote:
> Hi Ihe,
>
> Thanks for walking though the solution as I'm sure it will help
> others. Amazingly my mindset was exactly the same as yours, trying the
> XPath remove and replace before tearing some hair out an moving to the
> key solution proposed by David.
>
> As with any sample code I have run into a fringe scenario that has got
> me thinking of the "context" that the "use" statement,, ummm, uses.
> The fringe scenario comes up with nested allowable elements:
>
> <?xml version="1.0"?>
> <root>
>        <change-begin/>
>        <a>
>                <p>Foo<change-end/></p>
>        </a>
>        <change-begin/>
>        <b>
>                <d>
>                        <t>Bar</t>
>                </d>
>                <d>
>                        <t>Foo <p>This</p> whatever</t>
>                </d>
>        </b>
>        <change-end/>
>        <p>Nothing <change-begin/>to worry<change-end/> about</p>
> <!-- Fringe scenario -->
>        <b>
>                <d>
>                        <t><change-begin/>This <p>and</p> <t>That</t> and
<p>that and </p> a</t>
>                </d>
>        </b>
>        <change-end/>
> </root>
>
> In the last case the key puts the <change-end/> in the wrong spot
>

Well first up I have to own up to an oversight- that meant that my
change-begins and change-ends both came at the start of the allowable
elements.

To fix it up the key added in step five needs to have a different name
(I followed the established convention of cb and ce) and the template
in step 4 now sandwiches the apply-templates between the copy-of's for
change-begin and change-end (code below).

As for skipping nested p|t, are you sure you will not have a scenario
where you will not have nested changes?


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0"
                exclude-result-prefixes="">

    <!-- STEP THREE Define a key to pair up a change to the allowable
element it should go into -->
    <xsl:key name="cb" match="*[not (self::p or self::t)]/change-begin"
            use="generate-id(following::*[self::p or self::t][1])"/>

    <!-- STEP FIVE By symmetry extend the key to pair up change-ends
to allowable elements -->
    <xsl:key name="ce" match="*[not (self::p or self::t)]/change-end"
            use="generate-id(preceding::*[self::p or self::t]
   [1])"/>

   <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <!-- STEP ONE Remove all change-begin and change-end elements -->
    <xsl:template match="change-begin|change-end"/>

    <!-- STEP TWO Restore all change-begin and change-ends that are
already in the correct place -->
    <xsl:template
match="p/change-begin|p/change-end|t/change-begin|t/change-end">
       <xsl:copy-of select="."/>
    </xsl:template>

    <!-- STEP FOUR USE the key in STEP THREE to insert the
change-begin's in the right place -->
    <xsl:template match="p|t">
	    <xsl:copy>
		 <xsl:copy-of select="key('cb', generate-id())"/>
	        <xsl:apply-templates/>
	        <xsl:copy-of select="key('ce', generate-id())"/>
	    </xsl:copy>
    </xsl:template>


</xsl:stylesheet>

Current Thread