With this xml structure :
<doc>
<members>
<member name="T:XXX">
</member>
<member name="F:YYY">
</member>
<member name="P:ZZZ">
</member>
<member name="T:XXX">
</member>
</doc>
I try to get all nodes following node with name attribute starting with 'T:' until the next node with name attribute starting with 'T:'.
Based on this stackoverflow topic (#40767321), I found an almost perfect answer.
With the xsl:key below, it takes the first T: node and all of the followers but it also includes the next T: node in the select. How can I exlude it ?
<xsl:key name="subMembers" match="member" use="generate-id(preceding-sibling::*[contains(@name, 'T:')][1])" />
Thanks for your help !
In the linked topic, which deals with ol
elements followed by div
elements, the key is only matching the div
elements. However, in your question, the T: nodes represent the ol
elements and the key is matching these elements.
You need to replace the key to ignore the T: nodes
<xsl:key name="subMembers" match="member[not(starts-with(@name, 'T:'))]" use="generate-id(preceding-sibling::*[starts-with(@name, 'T:')][1])" />
So, assuming you start off by selecting the T: nodes, you would select those nodes, and the associated nodes, like so:
<xsl:copy-of select="self::*|key('subMembers', generate-id())" />
(Or you could use xsl:for-each
or xsl:apply-templates
should you also wish to transform the group elements).
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="subMembers" match="member[not(starts-with(@name, 'T:'))]" use="generate-id(preceding-sibling::*[starts-with(@name, 'T:')][1])" />
<xsl:template match="members">
<members>
<xsl:for-each select="member[starts-with(@name, 'T:')]">
<group>
<xsl:copy-of select="self::*|key('subMembers', generate-id())" />
</group>
</xsl:for-each>
</members>
</xsl:template>
</xsl:stylesheet>