when concatenating two xsl variables i get : An XPath expression was expected to return a NodeSet

StackOverflow https://stackoverflow.com/questions/23405528

  •  13-07-2023
  •  | 
  •  

Question

Hello everyone let us say i have the following xml:

<root>
    <leader>
        <paragraph>
             first
        </paragraph>

        <paragraph>
             second
        </paragraph>
    </leader>

    <sub>
        <paragraph>
            third
        </paragraph>

        <paragraph>
            fourth
        </paragraph>
    </sub>
</root>

I then specify in my xsl some variables as such:

<xsl:variable name="first" select="root/leader/paragraph/text()" />
<xsl:variable name="second" select="root/sub/paragraph/text()" />
<xsl:variable name="third">
    <xsl:value-of select="$first" />
    <xsl:value-of select="$second" />
</xsl:variable>  

I would then expect the output to have concatenated all the text from all paragraph eleemtns together instead i get:

An XPath expression was expected to return a NodeSet

I am using xsl v2.0

Any help would be greatly appreciated.

Was it helpful?

Solution

You can still join the text nodes in XSLT 1.0, using a handy template that loops (for-each) over the text nodes. Alternatively, a recursive template could be used to achieve the same.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:apply-templates select="root"/>
  </xsl:template>

  <xsl:variable name="first" select="root/leader/paragraph/text()" />
  <xsl:variable name="second" select="root/sub/paragraph/text()" />
  <xsl:variable name="third" select="$first|$second"/>

  <xsl:template match="root">
    <joined-string>
      <xsl:call-template name="join">
        <xsl:with-param name="list" select="$third"/>
      </xsl:call-template>
    </joined-string>
  </xsl:template>

  <xsl:template name="join">
    <xsl:param name="list" />
    <xsl:param name="separator" select="' '"/>

    <xsl:for-each select="$list">
      <xsl:value-of select="normalize-space(.)" />
      <xsl:if test="position() != last()">
        <xsl:value-of select="$separator" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Result:

<?xml version="1.0" encoding="utf-8"?>
<joined-string>first second third fourth</joined-string>

If you want all text nodes of all paragraphs, I recommend the following simplified template:

  <xsl:template match="root">
    <joined-string>
      <xsl:call-template name="join">
        <xsl:with-param name="list" select="//paragraph/text()"/>
      </xsl:call-template>
    </joined-string>
  </xsl:template>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top