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>
|