I need to change the snippet below into a hierarchical structure by grouping related elements under new group element. XSLT sounds like the appropriate technology to use here but I don't know enough about it to assess if it's capable of what I need. An example grouping criteria is "1 'd' node followed by some number of '3' nodes, followed by 1 'f' node". I have to perform this task for several separate criteria, so I'd like to know if queries of that nature are possible in XSLT or if I would be better served just giving up and processing the DOM procedurally. I'm completely open to other strategies, as well. For a specific example, I need to convert this-
<root>
<a>foo</a>
<b>bar</b>
<c>baz</c>
<d>location</d>
<e>3.14</e>
<e>6.02</e>
<e>1.23</e>
<f>2015</f>
<d>location</d>
<e>3.14</e>
<e>6.02</e>
<f>2015</f>
</root>
Into this-
<root>
<a>foo</a>
<b>bar</b>
<c>baz</c>
<sample>
<d>location</d>
<e>3.14</e>
<e>6.02</e>
<e>1.23</e>
<f>2015</f>
</sample>
<sample>
<d>location</d>
<e>3.14</e>
<e>6.02</e>
<f>2015</f>
</sample>
</root>
If it is that you want to group the elements, starting-with d
, you can use the following approach.
XSLT-1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" />
<xsl:strip-space elements="*"/>
<!-- key to select following (e|f) elements using the first preceding d's id -->
<xsl:key name="following" match="e | f" use="generate-id(preceding::d[1])"/>
<!-- identity transform template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- template to group d and its following (e|f) elements under sample element-->
<xsl:template match="d">
<sample>
<xsl:copy-of select="current() | key('following', generate-id())"/>
</sample>
</xsl:template>
<!-- template to do nothing for e|f elements -->
<xsl:template match="e|f"/>
</xsl:stylesheet>
And, of course, XSLT isn't limited to such simple grouping.