Lee Passey
Lee Passey

Reputation: 3

XSLT create list from paragraphs

I have encountered a section of HTML from a well-known Sci-Fi publisher that attempts to mimic an ordered list using paragraphs as anonymous tags. A sample is as follows:

<p class="NL1">1. first list item.</p>
<p class="NL">2. second list item.</p>
<p class="NL">3. third list item.</p>
<p class="NLL">4. last list item.</p>

I want to use XSLT to convert this abomination to a real ordered list. What I have tried is:

    <xsl:template name="makeLi">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>

    <xsl:template match="p[@class='NL1' 
        and preceding-sibling::node()[not(self::p[@class='NL1'])]]" >
        <ol>
            <xsl:call-template name="makeLi"/>
            <xsl:apply-templates select="following-sibling::node()[(self::p[@class='NL'])
                or (self::p[@class='NLL'])]"/>
        </ol>
     </xsl:template>

    <xsl:template match="p[@class='NL'
        and preceding-sibling::node()[not(self::p[@class='NL'])]
        and preceding-sibling::node()[not(self::p[@class='NL1'])]]" >
        <xsl:call-template name="makeLi"/>
    </xsl:template>

    <xsl:template match="p[@class='NLL' and preceding-sibling::node()[not(self:::p)]]" >
            <xsl:call-template name="makeLi"/>
    </xsl:template>

When I apply this transformation, what I end up with is:

<ol>
  <li>1. first list item.</li>
  <li>2. second list item.</li>
  <li>3. third list item.</li>
  <li>4. fourth list item.</li>
</ol>
<ul>
  <li>2. second list item.</li>
  <li>3. third list item.</li>
  <li>4. fourth list item.</li>
</ul>

How can I prevent the "NL" and "NLL" classes from being processed a second time?

Upvotes: 0

Views: 72

Answers (1)

Michael Kay
Michael Kay

Reputation: 163342

With XSLT 1.0, sibling recursion is the way to go, and you're on the right lines. Not tested, but something like this:

<xsl:template match="p[@class='NL1']" mode="normal">
  <ol>
    <xsl:call-template name="makeLi"/>
    <xsl:apply-templates select="following-sibling::p[1]" mode="list"/>
  </ol>
</xsl:template>

<xsl:template match="p[@class='NL']" mode="list">
  <xsl:call-template name="makeLi"/>
  <xsl:apply-templates select="following-sibling::p[1]" mode="list"/>
</xsl:template>

<xsl:template match="p[@class='NLL']" mode="list">
  <xsl:call-template name="makeLi"/>
</xsl:template>

<xsl:template match="p[@class='NL' or @class='NLL']" mode="normal"/>

I added mode="normal" for the default processing mode just for emphasis, you should leave it out if using the default (unnamed) mode.

Upvotes: 1

Related Questions