我有一些XML,我希望删除相同的连续子节点,这些子节点位于不同的父节点中。也就是说,如果一个孩子(在不同的父母)节点我的XML树连续出现两次或更多次,我想删除所有重复项。
我想到的重复节点是前两个<child>a</child>
节点中的<parent>
。
一个例子:
以下是源XML:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>a</child>
<child>bb</child>
<child>cc</child>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
<parent>
<child>a</child>
<child>bbbb</child>
<child>cccc</child>
</parent>
</root>
这是所需的XML:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>bb</child>
<child>cc</child>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
<parent>
<child>a</child>
<child>bbbb</child>
<child>cccc</child>
</parent>
</root>
只删除了一个元素,但如果开头有5个连续<child>a</child>
个节点(而不是2个),则会删除其中的4个节点。我正在使用XSLT 2.0。
我感谢任何帮助。
后续:
感谢Kirill,我得到了我想要的文档,但如果我有这样的XML文档,这会产生一个我没想到的新问题:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
</root>
我申请Kirill的XSLT,我明白了:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
</root>
如何删除<parent> </parent>
?对于我的应用程序,可能还有<parent>
的其他子元素,如果<child>
元素中没有<parent>
元素,则可以删除它们。
我有一个我不喜欢的解决方案是在第一个之后应用另一个转换。这仅在按顺序应用时才有效,我需要一个单独的XSLT文件,需要运行两个命令而不是一个。
这是:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent[not(child)]"/>
答案 0 :(得分:3)
使用:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="child[../preceding-sibling::parent[1]/child = .]"/>
</xsl:stylesheet>
答案 1 :(得分:2)
如果您能够使用XSLT 2.0,则问题解决如下:
<xsl:for-each-group select="parent" group-adjacent="child[1]">
<xsl:for-each select="current-group()">
<parent>
<xsl:if test="position()=1">
<xsl:copy-of select="current-group()[1]/child[1]"/>
</xsl:if>
<xsl:copy-of select="current-group()/child[position() gt 1]"/>
</parent>
</xsl:for-each>
</xsl:for-each-group>
答案 2 :(得分:0)
这回答了新增的后续问题:
如何删除
<parent> </parent>
?我在那里申请 可能是<parent>
的其他子元素,如果可以删除 元素中没有<child>
元素。
这个转换是Kirill的一个附加组件,可以完成所需的空parent
元素的清理,而不需要第二遍:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="child[../preceding-sibling::parent[1]/child = .]"/>
<xsl:template match=
"parent
[not(child
[not(. = ../preceding-sibling::parent[1]
/child
)
]
)
]"/>
</xsl:stylesheet>
应用于提供的XML文档:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
</root>
产生了想要的正确结果:
<root>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>
<parent>
<child>aaa</child>
<child>bbb</child>
<child>ccc</child>
</parent>
</root>