是否可以合并相同指定类型的每个节点序列? (在这种情况下为'aaa')(不仅仅是第一次出现的序列)
这是我的XML输入:
<block>
<aaa>text1</aaa>
<aaa>text2</aaa>
<aaa><xxx>text3</xxx></aaa>
<bbb>text4</bbb>
<aaa>text5</aaa>
<bbb><yyy>text6</yyy></bbb>
<bbb>text7</bbb>
<aaa>text8</aaa>
<aaa><zzz>text9</zzz></aaa>
<aaa>texta</aaa>
</block>
我想要关注输出:
<block>
<aaa>text1text2<xxx>text3</xxx></aaa>
<bbb>text4</bbb>
<aaa>text5</aaa>
<bbb><yyy>text6</yyy></bbb>
<bbb>text7</bbb>
<aaa>text8<zzz>text9</zzz>texta</aaa>
</block>
任何帮助表示赞赏
答案 0 :(得分:0)
假设您只有一个block
,Muenchian method是最优化的方式:
<!-- group nodes by name -->
<xsl:key name="block-children-by-name" match="block/*" use="name()"/>
<!-- for nodes that aren't first in their group, no output -->
<xsl:template match="block/*" />
<!-- for nodes that are first in their group, combine group children and output -->
<xsl:template match="block/*[generate-id() =
generate-id(key('block-children-by-name', name())[1])]">
<xsl:copy>
<xsl:copy-of select="key('block-children-by-name', name())/*"/>
</xsl:copy>
</xsl:template>
请注意,这仅合并子节点,而不是例如aaa
和bbb
本身可能出现的任何属性。
答案 1 :(得分:0)
这是另一种方法。
首先,匹配块元素的所有子节点
<xsl:template match="block/child::*">
接下来,检查元素的最直接兄弟是否有不同的名称,表明这是一个或多个相邻元素中的第一个:
<xsl:if test="local-name(preceding-sibling::*[position()=1]) != $name">
如果是,您可以复制该节点。然后,您需要复制具有相同名称的以下兄弟姐妹。我这样做是通过递归调用每个紧跟在兄弟之后使用相同名称
的模板<xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/>
将所有这些放在一起给出了
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<!-- Match children of the block element -->
<xsl:template match="block/child::*">
<xsl:variable name="name" select="local-name()"/>
<!-- Is this the first element in a sequence? -->
<xsl:if test="local-name(preceding-sibling::*[position()=1]) != $name">
<xsl:copy>
<xsl:apply-templates />
<!-- Match the next sibling if it has the same name -->
<xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!-- Recursive template used to match the next sibling if it has the same name -->
<xsl:template match="block/child::*" mode="next">
<xsl:variable name="name" select="local-name()"/>
<xsl:apply-templates />
<xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/>
</xsl:template>
<!-- Template used to copy a generic node -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
这是另一种方法,不使用递归模板。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="aaa">
<xsl:if test="not(preceding-sibling::*[1]/self::aaa)">
<xsl:variable name="following"
select="following-sibling::aaa[
not(preceding-sibling::*[
not(self::aaa) and
not(following-sibling::aaa = current())
])
]"/>
<xsl:copy>
<xsl:apply-templates select="$following/@*"/>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="$following/node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
用于选择与当前节点合并的以下兄弟aaa
节点的相当复杂的XPath表达式:
following-sibling::aaa[ # following 'aaa' siblings
not(preceding-sibling::*[ # if they are not preceded by
not(self::aaa) and # a non-'aaa' node
not(following-sibling::aaa = current()) # after the current node
])
]