从开头和结尾删除某些节点,并删除

时间:2016-12-02 08:57:45

标签: xslt-2.0

考虑这个XML:

<a>
   <b>something</b>
   <b>something</b>
   <M>other</M>
   <b>something</b>
   <b>something</b>
   <N>else</N>
   <b>something</b>
   <b>something</b>
   <b>something</b>
</a>

现在我要删除所有&#34; b&#34;在开始或结束时,如果它们位于不同节点之间,我只想输出一个节点。所以这将是理想的输出:

<a>
   <M>other</M>
   <b>something</b>
   <N>else</N>
</a>

我不知道有多少&#34; b&#34;并且我不知道其他节点名称是什么。开始很简单:删除所有&#34; b&#34;当他们关注&#34; b&#34;:

<xsl:template match="b[preceding-sibling::*[1][self::b]]"/>

然后删除第一个&#34; b&#34;:

<xsl:template match="b[position= 1]"/>

最后一个如果只有一个&#34; b&#34;:

<xsl:template match="b[position= last()]"/>

但是我无法获得最后三个中的第一个&#34; b&#34; s。测试应该说:如果只是&#34; b&#34;但是没有其他任何内容可以删除&#34; b&#34;。我发现的一些解决方案使用了分组,但由于节点的顺序很重要,在这里似乎没什么帮助。

1 个答案:

答案 0 :(得分:1)

我建议使用xsl:for-each-group,如下所示:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    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="a">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="boolean(self::b)">
                <xsl:choose>
                    <xsl:when test="not(current-grouping-key())">
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:when>
                    <xsl:when test="not(position() = (1, last()))">
                        <xsl:apply-templates select="."/>
                    </xsl:when>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

改变

<a>
    <b>1</b>
    <b>2</b>
    <M>foo</M>
    <b>3</b>
    <b>4</b>
    <N>bar</N>
    <b>5</b>
    <b>6</b>
    <b>7</b>
</a>

进入

<a>
   <M>foo</M>
   <b>3</b>
   <N>bar</N>
</a>