Stanislav Ilichev
Stanislav Ilichev

Reputation: 195

Performing transformation with xslt 2.0 how do I get quoted values separated with a delimiter?

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">&quot;</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

Answers (2)

uL1
uL1

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('&quot;', $i/@name, '&quot;'), ' , ')"/>
</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">&quot;</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

Daniel Haley
Daniel Haley

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">&quot;</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('&quot;',
      string-join($input,'&quot;, &quot;'),
      '&quot;')"/>
  </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

Related Questions