xml - XSLT - 识别具有相同属性值模式的连续节点

标签 xml xslt xslt-2.0

我有这样的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_start> 的新节点和<ss_end>通过覆盖以 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来覆盖特定节点<ss_start><ss_end>

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

但我正在努力寻找 id attr 从 ss 开始的连续节点并用 <ss_start> 覆盖它们和<ss_end> .

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

最佳答案

XSLT 1.0 同级递归

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

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

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

<?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 中的示例进行更新。

XSLT 2.0 组相邻

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

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

关于xml - XSLT - 识别具有相同属性值模式的连续节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32701706/

相关文章:

xml - XSLT 显示所有 XML 标签内容

xml - xslt 中的关键字计数

<xsl :output>: Which is the better choice? 中的 xml、html 或 xhtml

xslt - "context"关于调用模板参数的含义

java - 如何打印 org.jdom.Document 对象中的整个标签结构?

MySQL 查询将多个表中的媒体与另一个表中的元信息关联起来

xml - 使用 XML::Twig 对 XML 字符串进行基本解析

Android 从右到左 NavigationDrawer 菜单项不是 RTL

使用分隔符时的 XML 格式编号问题

xml - 如何在 XSLT 中使用 fn :replace(string, 模式,替换)