Cook Computing

XSLT Problem Continued

May 30, 2003 Written by Charles Cook

I'm learning a lot about XSLT. It seems that use of disable-output-escaping, such as in my recent post, is bad. It only works if the output is going to be used as text or parsed by an XML parser, not if it going to be passed on as a DOM, for example, (presumably because you are putting unescaped XML markup in a text node).

I stayed up late last night and found a better solution to the problem. This uses the following-sibling axis to traverse the list of formatting elements. Nested calls to apply-templates are used to nest the <i> elements within the <b> elements.


<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:choose>
      <xsl:when test="rPr/*">
        <xsl:apply-templates select="rPr/*[1]"/> 
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="t"/> 
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template> 

  <xsl:template match="r/rPr/b" priority="1">
    <xsl:call-template name="emit-format"/>
  </xsl:template> 

  <xsl:template match="r/rPr/i" priority="1">
    <xsl:call-template name="emit-format"/>
  </xsl:template> 

  <xsl:template match="r/rPr/*">
    <xsl:call-template name="ignore-format"/>
  </xsl:template> 

  <xsl:template name="emit-format">
    <xsl:element name="{name()}">
      <xsl:apply-templates select="following-sibling::*[1]"/>
      <xsl:if test="not(following-sibling::node())">
        <xsl:apply-templates select="../../t" />
      </xsl:if>
    </xsl:element>
  </xsl:template> 

  <xsl:template name="ignore-format">
    <xsl:apply-templates select="following-sibling::*[1]"/>
    <xsl:if test="not(following-sibling::node())">
      <xsl:apply-templates select="../../t" />
    </xsl:if>
  </xsl:template> 

</xsl:stylesheet> 

The one thing I don't understand about this is why I need to raise the priority for match="r/rPr/b" and match="r/rPr/i". As an XSLT neophyte I would expect them to be more specific than match="r/rPr/*" and so have higher priority.