Reputation: 35
I'm a complete novice with XSLT so apologies if solutions to other questions relating to loops would work for my problem but I've had no luck so far.
I have an XML file with multiple nodes such as the following:
<Roles>
<Role>User</Role>
<Purpose>General User</Purpose>
<Role>Staff</Role>
<Purpose>Company Staff</Purpose>
<Role>Admin</Role>
<Purpose>Administration</Purpose>
</Roles>
I need to loop through these nodes and print <Role> along with its matching <Purpose>. However, if I use a for-each loop it will iterate through the <Role>s fine but print the same <Purpose> for each (just the first Roles/Purpose element.
Is there any way I can sync them up so that, for example, when the for-each loop is on its second iteration it picks the second <Purpose> along with the second <Role> so it ends up something like this?
User - General User
Staff - Company Staff
Admin - Administration
I have been looking at using params such as the following but I get "element with-param is not allowed within that context" error when complining (probably my lack of XSLT understanding using it wrong).
<xsl:param name="i" select="1"/>
I have to keep the elements separate (i.e. I can't just do <Role>User - General User</Role> due to annoying formatting reasons but if anyone could think an alternative to loops which would work as well I would appreciate it.
Upvotes: 0
Views: 4357
Reputation: 14251
Use following-sibling
. Something like:
<xsl:for-each select="Role">
<xsl:value-of select="."/>
<xsl:text> - </xsl:text>
<xsl:value-of select="following-sibling::Purpose[1]"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
Works only in XSLT 1.0 (see comment Daniel Haley).
Upvotes: 1
Reputation: 52888
You can do this using the following-sibling::
axis. You'll want to select the first following Purpose
sibling.
There's already an answer using xsl:for-each
, so here's one using xsl:apply-templates
...
XML Input
<Roles>
<Role>User</Role>
<Purpose>General User</Purpose>
<Role>Staff</Role>
<Purpose>Company Staff</Purpose>
<Role>Admin</Role>
<Purpose>Administration</Purpose>
</Roles>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="Roles">
<xsl:copy>
<xsl:apply-templates select="Role"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Role">
<xsl:copy>
<xsl:value-of select="concat(., ' - ', following-sibling::Purpose[1])"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output (not sure if this is the output you want because you didn't specify, but it shows the concept at least)
<Roles>
<Role>User - General User</Role>
<Role>Staff - Company Staff</Role>
<Role>Admin - Administration</Role>
</Roles>
Upvotes: 1