Given this XML data:
<root> <item>apple</item> <item>orange</item> <item>banana</item> </root>
I can use this XSLT markup:
... <xsl:for-each select="root/item"> <xsl:value-of select="."/>, </xsl:for-each> ...
to get this result:
apple, orange, banana,
but how do I produce a list where the last comma is not present? I assume it can be done doing something along the lines of:
... <xsl:for-each select="root/item"> <xsl:value-of select="."/> <xsl:if test="...">,</xsl:if> </xsl:for-each> ...
but what should the test expression be?
I need some way to figure out how long the list is and where I currently am in the list, or, alternatively, if I am currently processing the last element in the list (which means I don't care how long it is or what the current position is).
Robert gave the classis
not(position() = last())
answer. This requires you to process the whole current node list to get context size, and in large input documents this might make the conversion consume more memory. Therefore, I normally invert the test to be the first thingA simple XPath 1.0 one-liner:
concat(., substring(',', 2 - (position() != last())))
Put it into this transformation:
and apply it to the XML document:
to get the wanted result:
apple,orange,banana
EDIT:
Here is a comment from Robert Rossney to this answer:
and here is my answer:
Guys, never shy from learning something new. In fact this is all Stack Overflow is about, isn't it? :)
or (perhaps more efficient, but you'd have to test):
Take a look at the
position()
,count()
andlast()
functions; e.g.,test="position() < last()"
.This is the way I got it working for me. I tested this against your list:
For an XSLT 2.0 option, you can use the
separator
attribute onxsl:value-of
.This
xsl:value-of
:would produce this output:
You could also use more than just a comma for a separator. For example, this:
Would produce the following output:
Another XSLT 2.0 option is
string-join()
...