Xml – Transforming XML mixed nodes with disable-output-escaping

xmlxslt

Variations on this question have been posted, but I couldn't find any that address the base case. I thought it would be good to have a canonical answer to the simplest version of the problem. This question assumes xslt 1.0.

I have an XML document that contains mixed nodes, e.g.:

<paragraph>
     This is some text that is <bold>bold</bold> 
     and this is some that is <italic>italicized.</italic>
</paragraph>

I would typically use a transformation that looks something like this:

<xsl:template match="bold">
    <b><xsl:apply-templates/></b>
</xsl:template>
<xsl:template match="italic">
    <i><xsl:apply-templates/></i>
</xsl:template>
<xsl:template match="paragraph">
    <p><xsl:apply-templates/></p>
</xsl:template>

which works great until I want to use disable-output-escaping="yes", which is an attribute of xsl:value-of. Is there a way to select the text-portion of the mixed node to which I can apply the value-of independent of the embedded nodes?

This, of course, doesn't work because I would lose the child nodes:

<xsl:template match="paragraph">
    <p><xsl:value-of select="." disable-output-escaping="yes"/></p>
</xsl:template>

I know the fact I am trying to do this probably represents an inherent problem in the way I am handling the XML, but much of the XML is being fairly-naively generated by (trusted) user input, and I am trying to avoid a lot of extra processing code between the XML->XSLT->HTML form (if possible).

Best Answer

If I understand you right, you want text nodes to come out as literal text (disable-output-escaping="yes"), but the rest of the transformation should work normally (<bold> to <b> etc.)

Template modes can help:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" />

  <xsl:template match="paragraph">
    <p>
      <xsl:apply-templates mode="literal" />
    </p>
  </xsl:template>

  <!-- literal templates (invoked in literal mode) -->
  <xsl:template match="bold" mode="literal">
    <b><xsl:apply-templates mode="literal"/></b>
  </xsl:template>
  <xsl:template match="italic" mode="literal">
    <i><xsl:apply-templates mode="literal"/></i>
  </xsl:template>
  <xsl:template match="text()" mode="literal">
    <xsl:value-of select="." disable-output-escaping="yes" />
  </xsl:template>

  <!-- normal templates (invoked when you don't use a template mode) -->
  <xsl:template match="bold">
    <b><xsl:apply-templates /></b>
  </xsl:template>
  <xsl:template match="italic">
    <i><xsl:apply-templates /></i>
  </xsl:template>

</xsl:stylesheet>
Related Topic