Reputation: 195
I have an xml to transform:
<root>
<item name="first" />
<item name="second" />
<item name="third" />
</root>
What I want to get is a string where every value is quoted and values are separated (order does not matter):
"first" , "second" , "third"
My question is how do I achieve this using xslt 2.0 properly?
Here is my solution that does not work as expected. So my co-question is - why it is not?
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns="urn:my.name.space"
version="2.0">
<xsl:output method="text" media-type="text/json"/>
<xsl:template match="root">
<xsl:value-of select="item/@name" separator=" , "/>
<xsl:text> :: </xsl:text>
<xsl:value-of select="item/ns:quotedString(@name)" separator=" , "/>
</xsl:template>
<xsl:function name="ns:quotedString">
<xsl:param name="input"/>
<xsl:variable name="quote">"</xsl:variable>
<xsl:value-of select="concat($quote, $input, $quote)"/>
</xsl:function>
</xsl:stylesheet>
This gives me:
first , second , third :: "second""third""first"
Note the separator is missing if I call my quoting function.
I apply transformation using Saxon-B 9.1.0.8.
Upvotes: 0
Views: 117
Reputation: 2167
There are multiple solutions to join a bunch of strings.
XPath for ... in ...
<xsl:template match="root">
<xsl:value-of select="string-join(for $i in item return concat('"', $i/@name, '"'), ' , ')"/>
</xsl:template>
<string-join>
joins the quotated strings of each item/@name
. The params of <string-join>
are strings.
Function call "ns:quotedString"
<xsl:template match="root">
<xsl:value-of select="item/ns:quotedString(@name)" separator=" , "/>
</xsl:template>
<xsl:function name="ns:quotedString">
<xsl:param name="input"/>
<xsl:variable name="quote">"</xsl:variable>
<xsl:sequence select="concat($quote, $input, $quote)"/>
</xsl:function>
This will answer your question about why is it not working. See the <xsl:sequence>
as last statement in function. The @separator
only works, if the <xsl:value select="...">
statement returns a sequence, in your case the return value is a single textnode.
Upvotes: 1
Reputation: 52888
Your function returns a text node and adjacent text nodes in the sequence are merged into a single text node. Have it return a sequence.
So change xsl:value
of to xsl:sequence
in your function...
<xsl:function name="ns:quotedString">
<xsl:param name="input"/>
<xsl:variable name="quote">"</xsl:variable>
<xsl:sequence select="concat($quote, $input, $quote)"/>
</xsl:function>
My preference is to just send the sequence to the function...
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns="urn:my.name.space"
version="2.0">
<xsl:output method="text" media-type="text/json"/>
<xsl:template match="root">
<xsl:value-of select="item/@name" separator=" , "/>
<xsl:text> :: </xsl:text>
<xsl:value-of select="ns:quotedString(item/@name)"/>
</xsl:template>
<xsl:function name="ns:quotedString">
<xsl:param name="input"/>
<xsl:value-of select="concat('"',
string-join($input,'", "'),
'"')"/>
</xsl:function>
</xsl:stylesheet>
Disclaimer: I don't have Saxon-B 9.1.0.8. to test with. I used Saxon-HE 9.5.1.7. to test.
Upvotes: 0