如何在嵌套后和使用 level="any" 后恢复 xsl 数字计数
How to resume xsl number count after nesting and while using level="any"
我正在尝试让 <xsl:number/>
恢复其计数器。但是,由于它使用的是 level="any"
,因此它会计算其先前同级元素的子元素,这是不可取的。
使用下面的示例代码,除了包含 Three
和 Four
的列表项外,一切看起来都是正确的。这些项目的计数为 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>
我正在尝试让 <xsl:number/>
恢复其计数器。但是,由于它使用的是 level="any"
,因此它会计算其先前同级元素的子元素,这是不可取的。
使用下面的示例代码,除了包含 Three
和 Four
的列表项外,一切看起来都是正确的。这些项目的计数为 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>