Cook Computing

Next XSLT Problem

June 3, 2003 Written by Charles Cook

The next problem looked tricky to begin with but once I realised I could use the following-sibling axis to traverse the list elements it soon panned out. The problem is to output an HTML unordered list where one or more adjacent <p> elements in the source document have contain a <listPr> element within a <pPr> element, i.e. the source document doesn't have an explicit list structure and lists are just adjacent paragraphs with list property elements. For example:


<body>
  <p>
    <r>
      <t>Before list</t> 
    </r>
  </p>
  <p>
    <pPr>
      <listPr></listPr>
    </pPr>
    <r>
      <t>first item</t> 
    </r>
  </p>
  <p>
    <pPr>
      <listPr></listPr>
    </pPr>
    <r>
      <t>Second item</t> 
    </r>
  </p>
<p>
  <r>
    <t>After list</t> 
  </r>
</p>
</body>

This should be transformed to something like this:


<p>Before list</p>
<ul><li>first item</li><li>Second item</li></ul>
<p>After list</p>

The difficulty is in placing the <ul> tags around the sequence of list items. My current solution involves finding the start of each list and then traversing the list recursively:


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

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

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

<xsl:template match="p[pPr/listPr]"> 
  <xsl:if test="not(preceding-sibling::p[1]/pPr/listPr)">
    <ul>
      <xsl:apply-templates select="." mode="listitem"/>
    </ul>
  </xsl:if>
</xsl:template> 

<xsl:template match="p" mode="listitem"> 
  <li>
    <xsl:apply-templates select="r/t"/>
  </li>
  <xsl:if test="following-sibling::p[1]/pPr/listPr">
    <xsl:apply-templates select="following-sibling::p[1]" mode="listitem" />
  </xsl:if>
</xsl:template> 

</xsl:stylesheet> 

Its so addictive at the moment, in the first flush of enthusiasm when learning something new, I could spend hours working on XSLT problems. I'm working my way thorugh a fairly complex transformation (the problems described are just the more interesting issues) and though I've reached the stage where I'm starting to get a feel for what I'm doing, I'm sure I'm not writing anywhere near optimal xsl yet. But its great fun getting there.