Search code examples
xmlxsltcdata

How to output CDATA from within an xsl:function call?


In my XSLT I'm trying to create elements inside a foreach and with the help of a function.

        <xsl:variable name="artistList" as="xs:string*"><xsl:apply-templates select="@artist"/></xsl:variable>
        <xsl:for-each select="$artistList">
            <xsl:comment select="."></xsl:comment>
            <xsl:copy-of select="cst:createArtistEntity('artist', ., 'Artist_')" />
        </xsl:for-each>

And the function itself as follows;

<xsl:function name="cst:createArtistEntity">
    <xsl:param name="name" />
    <xsl:param name="value" />
    <xsl:param name="artistPrefix" />
    <ChunkEntity>
        <EntityType>Artist</EntityType>
        <EntityReference><xsl:value-of select="cst-ext:digest(concat($artistPrefix, $value))" /></EntityReference>
        <Column>
            <Name><xsl:value-of select="$name"/></Name>
            <Value>
                <xsl:text disable-output-escaping="no">&lt;![CDATA[</xsl:text>
                <xsl:value-of select="$value" />
                <xsl:text disable-output-escaping="no">]]&gt;</xsl:text>
            </Value>
        </Column>
    </ChunkEntity>
</xsl:function>

The output should be like:

   <ChunkEntity>
      <EntityType>Artist</EntityType>
      <EntityReference>b325f9fd1f0642c310c0168e061805f8</EntityReference>
      <Column>
         <Name>artist</Name>
         <Value><![CDATA[Jon Bon Jovi]]></Value>
      </Column>
   </ChunkEntity>

However inside my foreach and with the use the function call, the angle brackets of the CDATA are kept as &gt; etc. When I copy the code inside the function straight into the loop, it all works. Setting disable-output-escaping to 'no' doesn't do anything.

So the problem is pinpointed to the fact that I'm using a function or a copy-of, but I'm confused. Does anyone have an idea?


Solution

  • Make two changes:

    1. In your function, set disable-output-escaping to yes:

      <Value>
          <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
          <xsl:value-of select="$value" />
          <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
      </Value>
      
    2. When calling your function, use xsl:sequence rather than xsl:copy-of:

      <xsl:sequence select="cst:createArtistEntity('artist', ., 'Artist_')" />
      

      Explanation: In the course of copying, xsl:copy-of re-escapes < and > whereas xsl:sequence references the original nodes without copying (or escaping).