Cook Computing

Beginning XSLT

May 29, 2003 Written by Charles Cook

I'm currently learning XSLT and I've come across a problem which I can solve but only in what seems like an inelegant way. Given this example source document:


<p>
  <r>
    <t>Some </t> 
  </r>
  <r>
    <rPr>
      <b /> 
      <i /> 
    </rPr>
    <t>formatted</t> 
  </r>
  <r>
    <rPr>
      <b /> 
    </rPr>
    <t> text.</t> 
  </r>
</p>

I want to transform it into something like this:


<p>Some <b><i>formatted</i></b><b> text.</b></p>

The problem is how to achieve the nesting of the text within the <b> and <i> tags. The following stylesheet seems to work but I don't like the use of the text elements with the disable-output-escaping attribute set. There is sure to be a right way of doing this but it has eluded me so far.


<xsl:stylesheet version = '1.0' 
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

  <xsl:template match="p">
    <p>
    <xsl:apply-templates select="r"/>
    </p>  
  </xsl:template> 

  <xsl:template match="r"> 

    <xsl:if test="rPr/b"> 
      <xsl:text disable-output-escaping="yes" >&amp;lt;b&amp;gt;</xsl:text>
    </xsl:if> 
    <xsl:if test="rPr/i"> 
      <xsl:text disable-output-escaping="yes" >&amp;lt;i&amp;gt;</xsl:text>
    </xsl:if> 

    <xsl:apply-templates select="t"/> 

    <xsl:if test="rPr/b"> 
      <xsl:text disable-output-escaping="yes" >&amp;lt;/i&amp;gt;</xsl:text>
    </xsl:if> 
    <xsl:if test="rPr/i"> 
        <xsl:text disable-output-escaping="yes" >&amp;lt;/b&amp;gt;</xsl:text>
    </xsl:if> 

  </xsl:template>

</xsl:stylesheet>

I've hugely simplified the source document and removed namespaces - for the purpose of illustrating the problem - but you may be able to guess what I'm trying to do from the element names.

UPDATE: I made the classic mistake of pasting a change into a sample without testing it. I've now corrected the final <r> element.