You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT处理含@pagebreak属性元素的模板匹配异常问题

Fixing Unapplied Templates for <para> and <table> with @pagebreak Attribute

I see the issue here—your XSLT is prioritizing the generic *[@pagebreak] template over the specific templates for <para> and <table>. That's why elements with the pagebreak attribute aren't getting converted to <p> tags (for para) or getting the id attribute (for table) like you expect.

Why This Happens

XSLT uses template priority rules: a template matching *[@pagebreak] has a higher priority than one matching just para or table. So when an element has that pagebreak attribute, it skips your specific element templates and runs the generic one instead.

Two Ways to Fix This


Option 1: Boost Priority for Specific Element Templates

We can explicitly set a higher priority on your <para> and <table> templates, then handle the pagebreak logic directly inside them. This keeps all related logic in one place for each element.

Here's the revised XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output indent="yes"/>

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

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

    <!-- Para template with higher priority, handles pagebreak -->
    <xsl:template match="para" priority="1">
        <!-- Output pagebreak div if the attribute exists -->
        <xsl:if test="@pagebreak='yes'">
            <div><pagebreak type="yes"/></div>
        </xsl:if>
        <p class="{concat('p_', count(preceding-sibling::para)+1)}">
            <!-- Don't copy the pagebreak attribute to the <p> tag -->
            <xsl:apply-templates select="node()"/>
        </p>
    </xsl:template>

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

    <!-- Table template with higher priority, handles pagebreak -->
    <xsl:template match="table" priority="1">
        <xsl:if test="@pagebreak='yes'">
            <div><pagebreak type="yes"/></div>
        </xsl:if>
        <xsl:variable name="num"><xsl:number/></xsl:variable>
        <table id="{concat('tab_', $num)}">
            <!-- Don't copy the pagebreak attribute to the <table> tag -->
            <xsl:apply-templates select="node()"/>
        </table>
    </xsl:template>

    <!-- Remove the old generic *[@pagebreak] template—we're handling it above -->
</xsl:stylesheet>

Key Changes:

  • Added priority="1" to the <para> and <table> templates (default priority is 0, so this ensures they take precedence over the generic attribute-matching template)
  • Added xsl:if blocks to output the pagebreak markup when the attribute is present
  • Stopped copying the pagebreak attribute to the final <p>/<table> tags (adjust this if you need to keep it)

Option 2: Modify the Generic Template to Call Specific Element Logic

If you want to keep the generic @pagebreak template, you can adjust it to first output the pagebreak markup, then invoke the specific element template using a mode to avoid recursion.

Here's how that looks:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output indent="yes"/>

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

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

    <xsl:template match="para">
        <p class="{concat('p_', count(preceding-sibling::para)+1)}">
            <xsl:apply-templates select="@* | node()"/>
        </p>
    </xsl:template>

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

    <xsl:template match="table">
        <xsl:variable name="num"><xsl:number/></xsl:variable>
        <table id="{concat('tab_', $num)}">
            <xsl:apply-templates select="@* | node()"/>
        </table>
    </xsl:template>

    <!-- Updated generic pagebreak template -->
    <xsl:template match="*[@pagebreak='yes']">
        <div><pagebreak type="yes"/></div>
        <!-- Call the element's template using a mode to avoid re-running this template -->
        <xsl:apply-templates select="." mode="pagebreak-handled"/>
    </xsl:template>

    <!-- Mode-specific templates for para and table -->
    <xsl:template match="para" mode="pagebreak-handled">
        <p class="{concat('p_', count(preceding-sibling::para)+1)}">
            <xsl:apply-templates select="node()"/>
        </p>
    </xsl:template>

    <xsl:template match="table" mode="pagebreak-handled">
        <xsl:variable name="num"><xsl:number/></xsl:variable>
        <table id="{concat('tab_', $num)}">
            <xsl:apply-templates select="node()"/>
        </table>
    </xsl:template>

    <!-- Fallback mode template for other elements with pagebreak -->
    <xsl:template match="*" mode="pagebreak-handled">
        <xsl:copy>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Key Changes:

  • The generic *[@pagebreak='yes'] template now outputs the pagebreak markup, then uses mode="pagebreak-handled" to call the element's specific template
  • Added mode-specific versions of the <para> and <table> templates that skip processing the pagebreak attribute
  • Included a fallback template for other elements with pagebreak to ensure they still get processed correctly

Testing It Out

Either option will produce the expected output:

  • <para pagebreak="yes"> becomes a <p> tag with the correct class, preceded by the pagebreak div
  • <table pagebreak="yes"> becomes a <table> tag with the generated id, preceded by the pagebreak div

内容的提问来源于stack exchange,提问作者Amrendra Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:43:03