XSLT - 使用模式在模板中循环

XSLT - looping in template using mode

我有一个这样的示例 xsl,

<doc>
    <p type="para">aaxx</p>
    <p type="paraX">aaxx</p>
    <p type="paraX">aaxx</p>
    <context type="para">aaxx</context>
    <p type="paraX">aaxx</p>
    <s>jksjdl</s>
    <p type="para">bbcc</p>
    <p type="paraX">kkll</p>
    <p type="paraX">aaxx</p>
    <p type="paraX">aaxx</p>
    <p type="paraX">aaxx</p>
    <p type="paraX">aaxx</p>
    <k>text</k>
    <p type="para">bbcc</p>
    <p type="paraX">aaxx</p>
    <p type="paraX">aaxx</p>
    <context type="para">aaxx</context>
    <p type="paraX">kkll</p>
    <t>text</t>
    <p type="paraX">aa</p>
    <p type="paraX">kddkll</p>
</doc>

我的要求是,

搜索任何 <p type="para"> 后跟类型以 paraX 开头的 p<context type="para”> 的任意组合,并将该内容插入 <section>.

所以,我的预期输出应该是这样的,

<doc>
    <section>
        <p type="para">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">aaxx</p>
    </section>
    <s>jksjdl</s>
    <section>
        <p type="para">bbcc</p>
        <p type="paraX">kkll</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
    </section>
    <k>text</k>
    <section>
        <p type="para">bbcc</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
    </section>
    <t>text</t>
    <p type="paraX">aa</p>
    <p type="paraX">kddkll</p>
</doc>

我已经编写了 XSLT 来做到这一点,

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

    <xsl:template match="p[@type='para']"/>

    <xsl:template match="p[@type='paraX']"/>

    <xsl:template match="p[@type='para']">
        <section>
            <p type="para">
                <xsl:apply-templates/>
            </p>
            <xsl:apply-templates select="following-sibling::*[1]" mode="box"/>
        </section>
    </xsl:template>

    <xsl:template match="p" mode="box">
        <p type="{@type}">
            <xsl:apply-templates/>
        </p>
        <xsl:apply-templates select="following-sibling::p[1][@type='paraX'] | following-sibling::context[1][@type='para']" mode="box"/>
    </xsl:template>

    <xsl:template match="context" mode="box">
        <context type="{@type}">
            <xsl:apply-templates/>
        </context>
        <xsl:apply-templates select="following-sibling::p[1][@type='paraX'] | following-sibling::context[1][@type='para']" mode="box"/>
    </xsl:template>

但它给出了以下输出,

<doc>
    <section>
        <p type="para">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
    </section>


    <context type="para">aaxx</context>

    <s>jksjdl</s>
    <section>
        <p type="para">bbcc</p>
        <p type="paraX">kkll</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
    </section>
    <k>text</k>
    <section>
        <p type="para">bbcc</p>
        <p type="paraX">aaxx</p>
        <p type="paraX">aaxx</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
        <p type="paraX">kkll</p>
        <context type="para">aaxx</context>
        <p type="paraX">kkll</p>
    </section>
    <context type="para">aaxx</context>
</doc>

知道如何修改我的模板以获得正确的输出吗?

您没有足够清楚地指定要求以确保代码正确,但对于提供的输入,以下内容可行:

<xsl:template match="doc">
<doc>
  <xsl:for-each-group select="*" 
    group-starting-with="p[@type='para'] | *[not(self::p | self::context)]">
    <xsl:choose>
     <xsl:when test="self::p">
      <section><xsl:copy-of select="current-group()"/></section>
     <xsl:when>
     <xsl:otherwise>
      <xsl:copy-of select="current-group()"/>
     </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</doc>
</xsl:template>

我确信您使用同级递归的方法可以奏效,但我个人认为使用 for-each-group 进行位置分组更加清晰且更易于调试。