从开头和结尾删除某些节点并删除其间的重复项
Delete certain nodes from the beginning and the end and remove duplicates in between
考虑这个 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>
现在我想删除开头或结尾的所有 "b",如果它们位于不同节点之间,我只想输出一个。所以这将是所需的输出:
<a>
<M>other</M>
<b>something</b>
<N>else</N>
</a>
我不知道有多少 "b" 也不知道其他节点的名称是什么。开始很简单:当 "b" 跟随 "b":
时删除所有 "b"
<xsl:template match="b[preceding-sibling::*[1][self::b]]"/>
然后去掉第一个"b":
<xsl:template match="b[position= 1]"/>
最后一个如果只有一个"b":
<xsl:template match="b[position= last()]"/>
但我无法摆脱最后三个 "b" 中的第一个。测试应该说:如果只有 "b" 但没有其他内容,则删除 "b"。我发现的一些解决方案利用了分组,但由于节点的顺序很重要,因此在这里似乎无济于事。
我建议使用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>
考虑这个 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>
现在我想删除开头或结尾的所有 "b",如果它们位于不同节点之间,我只想输出一个。所以这将是所需的输出:
<a>
<M>other</M>
<b>something</b>
<N>else</N>
</a>
我不知道有多少 "b" 也不知道其他节点的名称是什么。开始很简单:当 "b" 跟随 "b":
时删除所有 "b"<xsl:template match="b[preceding-sibling::*[1][self::b]]"/>
然后去掉第一个"b":
<xsl:template match="b[position= 1]"/>
最后一个如果只有一个"b":
<xsl:template match="b[position= last()]"/>
但我无法摆脱最后三个 "b" 中的第一个。测试应该说:如果只有 "b" 但没有其他内容,则删除 "b"。我发现的一些解决方案利用了分组,但由于节点的顺序很重要,因此在这里似乎无济于事。
我建议使用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>