Question

How can I get last position

<contrib contrib-type="author" corresp="no">
  <surname>Duan</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Ding</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Li</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Miao</surname>
</contrib>

This is the XSL

<xsl:template match="contrib">
  <xsl:choose>
    <xsl:when test="position()=last()">
      <xsl:apply-templates />
      <xsl:text> and </xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates/>
      <xsl:text>, </xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

I need this Output: Duan, Ding, Li and Miao

Can anyone tell me what's wrong with it? Thanks in advance.

Was it helpful?

Solution

You are already using the last() function, but possibly thinking it is not working. Although you have not shown the full XSLT, it is possible you are relying on XSLT's built-in templates to select the contrib elements. In this case, it is selecting nodes in the XML, not just elements, and the position() relates to the nodes just selected, including text nodes. The last contrib element is not the last node because there is a white-space node after the last element.

What you could do is use the strip-space command to remove such white-space nodes.

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*" />

    <xsl:template match="contrib">
      <xsl:choose>
        <xsl:when test="position()=last()">
          <xsl:text> and </xsl:text>
        </xsl:when>
        <xsl:when test="position() > 1">
          <xsl:text>, </xsl:text>
        </xsl:when>
      </xsl:choose>
      <xsl:apply-templates />
    </xsl:template>
</xsl:stylesheet>

However, this may not work if there are other elements in the XML. So, to get around this, you could explicitly select the contrib elements, in which case position would pick up the last one. Try this XSLT too

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*" />

    <xsl:template match="/*">
      <xsl:apply-templates select="contrib" />
    </xsl:template>

    <xsl:template match="contrib">
      <xsl:choose>
        <xsl:when test="position()=last()">
          <xsl:text> and </xsl:text>
        </xsl:when>
        <xsl:when test="position() > 1">
          <xsl:text>, </xsl:text>
        </xsl:when>
      </xsl:choose>
      <xsl:apply-templates />
    </xsl:template>
</xsl:stylesheet>

OTHER TIPS

Your code works in a proper context (add a root template) the function position() doesn't work without it.

Check it out:

<?xml version="1.0" encoding="UTF-8"?>
<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="/"> 
<contribs>
<xsl:apply-templates/>
</contribs>
</xsl:template>

<!-- your template -->

<xsl:template match="contrib">
  <xsl:choose>
    <xsl:when test="position()=last()">
      <xsl:apply-templates />
      <xsl:text> and </xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates/>
      <xsl:text>, </xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

You must also wrap convenient-ly your xml data (multiroot xml is not correct)

<?xml version="1.0" encoding="UTF-8"?>

<doc>

<contrib contrib-type="author" corresp="no">
  <surname>Duan</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Ding</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Li</surname>
</contrib>
<contrib contrib-type="author" corresp="no">
  <surname>Miao</surname>
</contrib>

</doc>

For a nicer result you have to shift the "and" text part after

position()=last()-1

and leave text after position()=last() empty, but this can be easily deduced and executed, isn't it ?

This looks as a poorly prepared homework exercise!!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top