To continue on my previous example on slicing (I made the term up, by the way), today we'll do something a little different.
Let's say that instead of just inserting the slice elements and a few items, we want to copy the whole tree n times (where n is the number of slices), each time with a different slice of items. That includes elements beyond the things we're currently slicing.
So let's say we have this document, similar to the previous one.
<group groupattribute='1'> <repeat-me>each time</repeat-me> <item item='1'>1 <sub>text</sub> </item> <item item='2'>2 <sub>text</sub> </item> <item item='3'>3 <sub>text</sub> </item> <item item='4'>4 <sub>text</sub> </item> <item item='5'>5 <sub>text</sub> </item></group>
And we want to get this effect.
<root> <group groupattribute="1"> <repeat-me>each time</repeat-me> <item item="1">1 <sub>text</sub></item> <item item="2">2 <sub>text</sub></item> </group> <group groupattribute="1"> <repeat-me>each time</repeat-me> <item item="3">3 <sub>text</sub></item> <item item="4">4 <sub>text</sub></item> </group> <group groupattribute="1"> <repeat-me>each time</repeat-me> <item item="5">5 <sub>text</sub></item> </group></root>
Here is a stylesheet that can accomplish this, using parameters to pass around the replacements nodes for each copy of the tree. As always, variations in the comments are welcome.
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> <xsl:output method='xml' indent='yes'/> <!-- Just copy everything. --> <xsl:template match='@* | node()' mode='everything'> <xsl:copy> <xsl:apply-templates select='@* | node()' mode='everything'/> </xsl:copy> </xsl:template> <!-- Copy everything but replace items with the replacement parameter. --> <xsl:template match='@* | node()' mode='withreplacement'> <xsl:param name='replacement' /> <xsl:copy> <!-- Copy everything except item elements. --> <xsl:apply-templates select='@* | node()[local-name() != "item"]' mode='withreplacement'> <xsl:with-param name='replacement' select='$replacement' /> </xsl:apply-templates> <!-- If this is where items are, apply the replacement node-set. --> <xsl:if test='item'> <xsl:apply-templates select='$replacement' mode='everything' /> </xsl:if> </xsl:copy> </xsl:template> <!-- We matched the first of a slice of items. Copy everything from the root, passing the current item and its sibling(s) as the replacement. --> <xsl:template match='item' mode='firstofslice'> <xsl:apply-templates select='/group' mode='withreplacement'> <xsl:with-param name='replacement' select='. | following-sibling::item[1]' /> </xsl:apply-templates> </xsl:template> <!-- Match to root, and put everything under a single element. --> <xsl:template match='/'> <root> <!-- Grab every second item to create a new group. --> <xsl:apply-templates select='group/item[position() mod 2 = 1]' mode='firstofslice' /> </root> </xsl:template></xsl:stylesheet>
Enjoy!
PingBack from http://www.alvinashcraft.com/2009/06/05/dew-drop-june-5-2009/