如何在嵌套后和使用 level="any" 后恢复 xsl 数字计数

How to resume xsl number count after nesting and while using level="any"

我正在尝试让 <xsl:number/> 恢复其计数器。但是,由于它使用的是 level="any",因此它会计算其先前同级元素的子元素,这是不可取的。

使用下面的示例代码,除了包含 ThreeFour 的列表项外,一切看起来都是正确的。这些项目的计数为 5 和 6,因为计数器正在使用嵌套在项目 Two 中的项目,而不是从项目 Two 本身停止的地方继续。

样本输入XML:

<body>
    <div class="list-wrapper">
        <ol>
            <li>One</li>
            <li><span>Two</span>
                <ol>
                    <li>AAA</li>
                    <li>BBB</li>
                </ol>
                <div class="list-wrapper">
                    <ol>
                        <li>CCC</li>
                        <li>DDD</li>
                    </ol>
                    <ol>
                        <li>EEE</li>
                        <li>FFF</li>
                    </ol>
                </div>
                <ol>
                    <li>GGG</li>
                    <li>HHH</li>
                </ol>
            </li>
        </ol>
        <ol>
            <li>Three</li>
            <li>Four</li>
        </ol>
    </div>
    <div class="list-wrapper">
        <ol>
            <li>Five</li>
            <li>Six</li>
        </ol>
        <ol>
            <li>Seven</li>
            <li>Eight</li>
        </ol>
    </div>
</body>

示例样式表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="body">
        <fo:root>
            <xsl:apply-templates />
        </fo:root>
    </xsl:template>

    <xsl:template match="div[@class='list-wrapper']">
        <fo:list-block>
            <xsl:apply-templates  mode="list-wrapper" />
        </fo:list-block>
    </xsl:template>

    <xsl:template match="ol" mode="list-wrapper">
        <xsl:apply-templates mode="list-wrapper" />
    </xsl:template>

    <xsl:template match="li" mode="list-wrapper">
        <fo:list-item>
            <fo:list-item-label>
                <xsl:number format="1." count="div[@class='list-wrapper']/ol/li" from="div[@class='list-wrapper']" level="any" />
            </fo:list-item-label>
            <fo:list-item-body>
                <xsl:apply-templates />
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>

    <xsl:template match="ol">
        <fo:list-block>
            <xsl:apply-templates />
        </fo:list-block>
    </xsl:template>

    <xsl:template match="li">
        <fo:list-item>
            <fo:list-item-label>
                <xsl:number format="1."/>
            </fo:list-item-label>
            <fo:list-item-body>
                <xsl:apply-templates />
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>
</xsl:stylesheet>

看来我可以通过使用 xsl:for-each 仅处理 div[@class='list-wrapper'] 的直接子代来解决嵌套问题。

现在我可以根据需要简单地使用 position() 为每个节点编号。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="body">
        <fo:root>
            <xsl:apply-templates />
        </fo:root>
    </xsl:template>

    <xsl:template match="div[@class='list-wrapper']">
        <fo:list-block>
            <xsl:for-each select="ol/li">
                <xsl:call-template name="process-ordered-list" />
            </xsl:for-each>
        </fo:list-block>
    </xsl:template>

    <xsl:template match="li">
        <xsl:call-template name="process-ordered-list" />
    </xsl:template>

    <xsl:template name="process-ordered-list">
        <fo:list-item>
            <fo:list-item-label>
                <xsl:number format="1." value="position()" />
            </fo:list-item-label>
            <fo:list-item-body>
                <xsl:apply-templates />
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>

    <xsl:template match="ol">
        <fo:list-block>
            <xsl:apply-templates />
        </fo:list-block>
    </xsl:template>
</xsl:stylesheet>

我可以通过将 for-each 替换为 apply-templates 来简化模板。

这个解决方案看起来最好。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="body">
        <fo:root>
            <xsl:apply-templates />
        </fo:root>
    </xsl:template>

    <xsl:template match="div[@class='list-wrapper']">
        <fo:list-block>
            <xsl:apply-templates select="ol/li" />
        </fo:list-block>
    </xsl:template>

    <xsl:template match="ol">
        <fo:list-block>
            <xsl:apply-templates />
        </fo:list-block>
    </xsl:template>

    <xsl:template match="ol/li">
        <fo:list-item>
            <fo:list-item-label>
                <xsl:number format="1." value="position()" />
            </fo:list-item-label>
            <fo:list-item-body>
                <xsl:apply-templates />
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>
</xsl:stylesheet>