We cannot be sure without looking at the whole XSLT, but you probably have an ol
directly nested inside another ol
in your input. In such a situation, your XSLT would producec an fo:list-block
inside another one, which is a violation of fo:list-block
content type, and that's what FOP is complaining about.
If that's the case, you have to modify your stylesheet to better handle nested lists, for example creating an fo:list-item
whose fo:list-item-label
is just an empty fo:block
, and whose fo:list-item-body
contains the inner fo:list-block
:
<xsl:template match="ol|OL">
<xsl:choose>
<xsl:when test="parent::ol or parent::OL">
<!-- create a list item with empty label -->
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block/>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<xsl:apply-templates select="." mode="nestingOk"/>
</fo:list-item-body>
</fo:list-item>
</xsl:when>
<xsl:otherwise>
<!-- nothing special to do -->
<xsl:apply-templates select="." mode="nestingOk"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ol|OL" mode="nestingOk">
<!-- this is just like in your old template -->
<fo:list-block provisional-distance-between-starts="1cm"
provisional-label-separation="0.5cm">
<xsl:attribute name="space-after">
<xsl:choose>
<xsl:when test="ancestor::ul or ancestor::ol">
<xsl:text>0pt</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>12pt</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="start-indent">
<xsl:variable name="ancestors">
<xsl:choose>
<xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
<xsl:value-of select="1 +
(count(ancestor::ol) +
count(ancestor::ul)) *
1.25"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>1</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($ancestors, 'cm')"/>
</xsl:attribute>
<xsl:apply-templates select="*"/>
</fo:list-block>
</xsl:template>
- a new template matching
ol|OL
has been added; it just checks whether the current list is directly nested inside another one, in which case an fo:list-item
is created to wrap the inner fo:list-block
(according to your preferences, you could use two simpler templates instead, with a node test in the matching expression)
- your old template is given a different mode (I deliberately left its content unchanged), so that it is called by the new one when we are sure that the
fo:list-block
will be in a valid position
However the root cause of the problem is an invalid input, as neither HTML nor xhtml allow nested lists made like this:
<!-- this is NOT valid! -->
<ol>
<li>alpha</li>
<li>bravo</li>
<li>charlie</li>
<ol>
<li>lorem</li>
<li>ipsum</li>
</ol>
</ol>
They should instead be like this:
<!-- this is valid -->
<ol>
<li>alpha</li>
<li>bravo</li>
<li>charlie
<ol>
<li>lorem</li>
<li>ipsum</li>
</ol>
</li>
</ol>
Complicating your stylesheet to handle correctly an invalid input probably means opening a can of worms; for example, in your original stylesheet the template matches ol|OL
, but then in other expressions you just consider ancestor::ul or ancestor::ol
without taking into account OL
or UL
ancestors ...
In conclusion, I would strongly suggest following Tony Graham's advice and normalize your input before applying the XSLT, which could also be simplified a bit.