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

时间:2016-07-14 07:29:43

标签: xml xslt xslt-2.0

我有一个像这样的样本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">,然后搜索p的任意组合,其类型以paraX<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>

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

1 个答案:

答案 0 :(得分:2)

您尚未明确指定要求以确保正确获取代码,但对于提供的输入,以下内容可行:

<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>

我确定您使用兄弟递归的方法可以起作用,但我个人认为,对于每个组的位置分组更清晰,更容易调试。