XSLT - 识别具有相同属性值模式的连续节点 [英] XSLT - Identify consecutive nodes which has same patterns of attribute values

查看:26
本文介绍了XSLT - 识别具有相同属性值模式的连续节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的 xml,

<section>
        <p id="ss_main">aa</p>
        <p id="ss_chap">bb</p>
        <p id="main">cc</p>
        <p id="main">dd</p>
        <p id="main">ee</p>
        <p id="ss_main">ff</p>
        <p id="main">gg</p>
        <p id="main">hh</p>
        <p id="main">ii</p>
        <p id="main">jj</p>
        <p id="ss_chap">xx</p>
        <p id="ss_main">yy</p>
        <p id="ss_chap">zz</p>
    </section>

我的要求是放置名为 的新节点,覆盖现有节点,以 ss 开头.

what my requirement is place new nodes named <ss_start> and <ss_end> by covering existing nodes witch are start with ss.

所以输出应该是,

<section>
        <ss_start/>
        <p id="ss_main">aa</p>
        <p id="ss_chap">bb</p>
        <ss_end/>
        <p id="main">cc</p>
        <p id="main">dd</p>
        <p id="main">ee</p>
        <ss_start/>
        <p id="ss_main">ff</p>
        <ss_end/>
        <p id="main">gg</p>
        <p id="main">hh</p>
        <p id="main">ii</p>
        <p id="main">jj</p>
        <ss_start/>
        <p id="ss_chap">xx</p>
        <p id="ss_main">yy</p>
        <p id="ss_chap">zz</p>
        <ss_end/>
    </section>

我可以通过

<xsl:template match="p[@id='ss_main']">
        <ss_start/>
        <p id="ss_main"><xsl:apply-templates/></p>
        <ss_end/>
    </xsl:template>

但我正在努力寻找从 ss 开始的 id attr 的连续节点,并通过 <ss_start><ss_end>.

but I'm struggling to find consecutive nodes that id attr starting from ss and cover them by <ss_start> and <ss_end>.

谁能建议我一种方法,我该怎么做?

Can anyone suggest me a method how can I do this?

推荐答案

XSLT 1.0 兄弟递归

在 XSLT 1.0 中,您可以按如下方式执行此操作,它使用一种称为 同级递归 的技术(尽管 同级遍历 可能是一个更好的术语).

XSLT 1.0 sibling recursion

In XSLT 1.0 you can do this as follows, which uses a technique called sibling recursion (though sibling traversal is probably a better term).

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes" />

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

    <xsl:template match="section">
        <xsl:copy>
            <xsl:apply-templates select="*[1]" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="section/*[starts-with(@id, 'ss')]" priority="5">
        <xsl:if test="self::*[not(preceding-sibling::*[1][starts-with(@id, 'ss')])]">
            <ss_start />
        </xsl:if>
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
        <xsl:if test="self::*[not(following-sibling::*[1][starts-with(@id, 'ss')])]">
            <ss_end />
        </xsl:if>
        <xsl:apply-templates select="following-sibling::*[1]" />
    </xsl:template>

    <xsl:template match="section/*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::*[1]" />
    </xsl:template>

</xsl:stylesheet>

当针对您的输入运行时,将创建此输出:

Which, when run against your input, will create this output:

<?xml version="1.0" encoding="UTF-8"?>
<section>
   <ss_start/>
   <p id="ss_main">aa</p>
   <p id="ss_chap">bb</p>
   <ss_end/>
   <p id="main">cc</p>
   <p id="main">dd</p>
   <p id="main">ee</p>
   <ss_start/>
   <p id="ss_main">ff</p>
   <ss_end/>
   <p id="main">gg</p>
   <p id="main">hh</p>
   <p id="main">ii</p>
   <p id="main">jj</p>
   <ss_start/>
   <p id="ss_chap">xx</p>
   <p id="ss_main">yy</p>
   <p id="ss_chap">zz</p>
   <ss_end/>
</section>

我现在看到您用 xslt-2.0 标记了您的问题,这意味着您可以使用分组.我将尝试使用 XSLT 2.0 中的示例进行更新.

I see now that you tagged your question with xslt-2.0, which means you can use grouping. I'll try to update with an example in XSLT 2.0.

在 XSLT 2.0 中,您可以使用布尔值 true/false 作为组相邻分组键,如下所示,这比上面的 XSLT 1.0 代码要短很多:

In XSLT 2.0, you can use a boolean true/false as the the group-adjacent grouping key as follows, which is quite a bit shorter than the XSLT 1.0 code above:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    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="section">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="starts-with(@id, 'ss')">
                <xsl:if test="current-grouping-key()"><ss_start /></xsl:if>
                <xsl:apply-templates select="current-group()" />
                <xsl:if test="current-grouping-key()"><ss_end /></xsl:if>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

这篇关于XSLT - 识别具有相同属性值模式的连续节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆