简体   繁体   中英

XSLT for-each loop iterating through 2 elements

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 (ie 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.

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>

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>&#xa;</xsl:text>
</xsl:for-each>

Works only in XSLT 1.0 (see comment Daniel Haley).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM