Created
May 6, 2011 23:11
-
-
Save kaero/959974 to your computer and use it in GitHub Desktop.
Solution for http://stackoverflow.com/questions/5907118
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<xsl:stylesheet version="1.0" | |
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |
<xsl:output method="xml" indent="yes"/> | |
<xsl:template match="group"> | |
<!--Start recursion over group children--> | |
<xsl:apply-templates select="*[1]" mode="group"/> | |
</xsl:template> | |
<!--Matches <group/> children--> | |
<xsl:template match="*" mode="group"> | |
<!--level is the index of elements combination from source group--> | |
<xsl:param name="level" select="0"/> | |
<xsl:variable name="name" select="name()"/> | |
<xsl:variable name="needs-group" select="count( preceding-sibling::*[ name() = $name ] ) = $level"/> | |
<!-- | |
Create new group if the current node position in the subset | |
of the siblings with the same name is equal current level | |
--> | |
<xsl:if test="$needs-group"> | |
<group> | |
<!-- | |
Search elements for the current level in the preceding-siblings. | |
Exclude elements with the same name as current. | |
--> | |
<xsl:apply-templates select="preceding-sibling::*[ name() != $name ]" mode="item-group"> | |
<xsl:with-param name="level" select="$level"/> | |
</xsl:apply-templates> | |
<!--Copy current element--> | |
<xsl:apply-templates select="."/> | |
<!-- | |
Search elements for the current level in the following-siblings. | |
--> | |
<xsl:apply-templates select="following-sibling::*[ name() != $name ]" mode="item-group"> | |
<xsl:with-param name="level" select="$level"/> | |
</xsl:apply-templates> | |
<!-- | |
You can join first and last apply-templates in the <group/> | |
if there is no need in the elements source order. | |
--> | |
<!-- | |
<xsl:apply-templates select="../*[ name() != $name ]" mode="item-group"> | |
<xsl:with-param name="level" select="$level"/> | |
</xsl:apply-templates> | |
--> | |
</group> | |
</xsl:if> | |
<!-- | |
Iterate over all children of current group. | |
This is good place to reduce recursion. | |
--> | |
<xsl:apply-templates select="following-sibling::*[1]" mode="group"> | |
<!--Increase level if group has been created: $needs-group true() -> 1, false() -> 0--> | |
<xsl:with-param name="level" select="$level + $needs-group"/> | |
</xsl:apply-templates> | |
</xsl:template> | |
<!--Matches <group/> child and decide include one into target group or not --> | |
<xsl:template match="*" mode="item-group"> | |
<xsl:param name="level"/> | |
<xsl:variable name="name" select="name()"/> | |
<!-- | |
Include current element to the group only if one of the conditions is true: | |
* the element position in the subset of elements with the same name equal the current level | |
* count of the elements with the same name in the source group is less, | |
than the level and this is the last element with the such name | |
--> | |
<xsl:if test="count( preceding-sibling::*[ name() = $name ] ) = $level or | |
( count( ../*[ name() = $name ] ) <= $level and not( following-sibling::*[ name() = $name ] ) )"> | |
<xsl:apply-templates select="."/> | |
</xsl:if> | |
</xsl:template> | |
<xsl:template match="@* | node()"> | |
<xsl:copy> | |
<xsl:apply-templates select="@* | node()"/> | |
</xsl:copy> | |
</xsl:template> | |
</xsl:stylesheet> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment