0

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 !

Mica
  • 159
  • 1
  • 10

1 Answers1

1

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>
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • Ok I think I got it, I'll try and come back to you! Thanks! – Mica May 24 '18 at 08:54
  • I tried and this is perfect ! I used a `xsl:foreach` and `call-template` instead of `xsl:copy-of`. Thanks again. – Mica May 24 '18 at 09:21