How do I apply templates to each selected node in a for-each?

二次信任 提交于 2019-12-05 05:01:52

I would agree with 'ndim' that you should probably restructure your XSLT to do away with the xsl:for-each loop.

Alternatively, you could amend the xsl:apply-templates to select the current track node within the xsl:for-each

<xsl:for-each select="track">
   <li>
      <xsl:apply-templates select="." />
   </li>
</xsl:for-each>

Keeping the xsl:for-each would, at least, allow you to sort the tracks in another order, if desired.

ndim

I'd restructure it a little (if you do not need the sorting the for-each approach makes possible):

<xsl:template match="/album">
  <ol>
    <xsl:apply-templates select="track"/>
  </ol>
</xsl:template>

<xsl:template match="track">
  <li><a href="{@id}"><xsl:apply-templates/></a></li>
<xsl:template>

This looks shorter and more to the point, IMHO.

I guess your

    <xsl:for-each select="track">
       <li><xsl:apply-templates/></li>
    </xsl:for-each>

walks through all track elements with the for-each, and then applies the default rules to its descendants. So the content of the for-each has the same context node as the match="track" template has, and thus the match="track" template never matches.

If you really want to use the for-each in that way, you will need to change either of the following two things in your approach:

  1. Add a name="track" attribute to the match="track" template, and then use <xsl:call-template/> from within the for-each (my idea, and worse than Tim C's)
  2. Use Tim C's solution using <xsl:apply-templates select="."/>. This has the advantage of avoiding naming and keeping the possibility to sort the tracks.

I think using apply-templates and template modes is the cleaner solution:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/">
    <body>
      <xsl:apply-templates select="album" mode="ol" />
    </body>
  </xsl:template>

  <xsl:template match="album" mode="ol">
    <ol>
      <xsl:apply-templates select="track" mode="li" />
    </ol>
  </xsl:template>

  <xsl:template match="track" mode="li">
    <li>
      <xsl:apply-templates select="." />
    </li>
  </xsl:template>

  <xsl:template match="track">
    <a href="{@id}">
      <xsl:value-of select="." />
    </a>
  </xsl:template>


</xsl:stylesheet>

results in:

<body>
  <ol>
    <li>
      <a href="shove">Somebody To Shove</a>
    </li>
    <li>
      <a href="gold">Black Gold</a>
    </li>
    <li>
      <a href="train">Runaway Train</a>
    </li>
  </ol>
</body>

The for-each statement changes the context node from album to track. The apply-templates call by default applies templates to the child nodes of the context node which in your case are the child nodes of the track element. Hence your template which matches 'track' never gets hit.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!