I need to build up a string using XSLT and separate each string with a comma but not include a comma after the last string. In my example below I will have a trailing comma if I have Distribution node and not a Note node for instance. I don't know of anyway to build up a string as a variable and then truncate the last character in XSLT. Also this is using the Microsoft XSLT engine.
My String =
<xsl:if test="Locality != ''">
<xsl:value-of select="Locality"/>,
</xsl:if>
<xsl:if test="CollectorAndNumber != ''">
<xsl:value-of select="CollectorAndNumber"/>,
</xsl:if>
<xsl:if test="Institution != ''">
<xsl:value-of select="Institution"/>,
</xsl:if>
<xsl:if test="Distribution != ''">
<xsl:value-of select="Distribution"/>,
</xsl:if>
<xsl:if test="Note != ''">
<xsl:value-of select="Note"/>
</xsl:if>
[Man there's gotta be a better way to enter into this question text box :( ]
Supposing you have something like the following input XML:
Then this template would do it:
Output on my system:
I think it might be useful to mention, position() doesn't work right when I use a complicated select that filters some nodes, in that case I came up which this trick:
you can define a string variable that hold value of nodes, separated by a specific character, then by using str:tokenize() you can create a complete node list which position works fine with it.
something like this:
Do you not have a value that is always going to be there? If you do then you can turn it around and put commas infront of everything apart from the first item (which would be your value that's always there).
This is very easy to accomplish with XSLT (No need to capture the results in a variable, or to use special named templates):
I. XSLT 1.0:
when this transformation is applied on the following XML document:
the wanted result is produced:
If the wanted elements should be produced not in document order (something not required in the question, but raised by Tomalak), it is still quite easy and elegant to achieve this:
Here the names of the wanted elements and their wanted order are provided in the string parameter
$porderedNames
, which contains a space-separated list of all wanted names.When the above transformation is applied on the same XML document, the wanted result is produced:
II. XSLT 2.0:
In XSLT this task is even simpler (again, no special function is necessary):
When this transformation is applied on the same XML document, the same correct result is produced:
Do note that the wanted elements will be produced in any desired order, because we are using the XPath 2.0 sequence type (vs the union in the XSLT 1.0 solution), which by definition contains items in any desired (specified) order.
This would be a bit messy but might do the trick if there's only a few elements like in your example:
I would prefer a short call-template to join the node values together. This also works if a node in the middle of your concatenated list, e.g.
Institution
, is missing:Here is a short example how to use it:
Sample input document:
XSL transformation:
Generated output document:
NB: If you were using XSLT/XPath 2.0 then there would be fn:string-join
which could be used as follows: