jbrehr
jbrehr

Reputation: 815

XSLT 2.0 how to test for position() in tokenize() on output

In XSLT 2.0 I have a parameter than comes in as a delimited string of document names like: ms609_0080.xml~ms609_0176.xml~ms609_0210.xml~ms609_0418.xml

I tokenize() this string and cycle through it with xsl:for-each to pass each document to a key. The results from the key I then assemble into a comma-delimited string to output to screen.

<xsl:variable name="list_of_corresp_events">
   <xsl:variable name ="tokenparam" select="tokenize($paramCorrespdocs,'~')"/>
   <xsl:for-each select="$tokenparam">
      <xsl:choose>
          <xsl:when test=".[position() != last()]">
               <xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/@xml:id"/>
          </xsl:when>
          <xsl:otherwise>
               <xsl:value-of select="concat(document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/@xml:id, ', ')"/>
          </xsl:otherwise>
      </xsl:choose>
   </xsl:for-each>
</xsl:variable>

Everything works fine except that when I output the variable $list_of_corresp_events it looks like the following, with an unexpected trailing comma:

ms609-0080-2, ms609-0176-1, ms609-0210-1, ms609-0418-1,

Ordinarily the last comma should not appear based on test=".[position() != last()]" ? Possibly positions don't work for tokenized data? I didn't see a way to apply string-join() to this.

Many thanks.

Upvotes: 1

Views: 1348

Answers (3)

Martin Honnen
Martin Honnen

Reputation: 167516

It seems you can simplify this to

<xsl:variable name="list_of_corresp_events">
   <xsl:value-of select="for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/@xml:id" separator=", "/>
</xsl:variable>

or with string-join

<xsl:variable name="list_of_corresp_events" select="string-join(for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/@xml:id, ', ')"/>

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163322

Improving on the solution from @zx485, try

<xsl:for-each select="$tokenparam">
   <xsl:if test="position()!=1">, </xsl:if>
   <xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/@xml:id"/>
</xsl:for-each>

Two things here:

(a) you don't need to repeat the same code in both conditional branches

(b) it's more efficient to output the comma separator before every item except the first, rather than after every item except the last. That's because evaluating last() involves an expensive look-ahead.

Upvotes: 2

zx485
zx485

Reputation: 29022

Change

<xsl:when test=".[position() != last()]">

to

<xsl:when test="position() != last()">

Then it should all work as desired.

Upvotes: 1

Related Questions