Next XSLT Problem
Tuesday 3 June 2003
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.