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 进行位置分组更加清晰且更易于调试。
我有一个这样的示例 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 进行位置分组更加清晰且更易于调试。