我有一个如下所示的xml文件,预期的输出应该只有基于recordNumber第一次出现的元素Xml文件如下:-
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<year>1985</year>
<recordNumber>100</recordNumber>
</cd>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<year>1988</year>
<recordNumber>101</recordNumber>
</cd>
<cd>
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<year>1982</year>
<recordNumber>102</recordNumber>
</cd>
<cd>
<title>Still got the blues</title>
<artist>Gary Moore</artist>
<year>1990</year>
<recordNumber>100</recordNumber>
</cd>
<cd>
<title>Eros</title>
<artist>Eros Ramazzotti</artist>
<year>1997</year>
<recordNumber>100</recordNumber>
</cd>
<cd>
<title>One night only</title>
<artist>Bee Gees</artist>
<year>1998</year>
<recordNumber>101</recordNumber>
</cd>
预期输出:-预期输出应该只包含基于recordNumber
第一次出现的元素 <?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<year>1985</year>
<recordNumber>100</recordNumber>
</cd>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<year>1988</year>
<recordNumber>101</recordNumber>
</cd>
<cd>
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<year>1982</year>
<recordNumber>102</recordNumber>
</cd>
更好的解决方案是使用XSLT 2.0分组:
<xsl:for-each-group select="cd" group-by="recordNumber">
<xsl:copy-of select="current-group()[1]"/>
</xsl:for-each-group>
虽然这个搜索非常密集,但它完成了任务:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="cd[count(preceding-sibling::cd[recordNumber = current()/recordNumber]) > 0]" />
</xsl:stylesheet>
首先,您显示的输入XML不是格式良好的。它缺少一个结束的</catalog>
标记。
你的要求很微不足道。它可以用两个模板来解决,一个执行单位变换,另一个防止cd
元素被发送到输出,如果它们前面有另一个具有相同recordNumber
元素的cd
元素。
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="cd[preceding::cd[recordNumber = current()/recordNumber]]"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
XML输出
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<year>1985</year>
<recordNumber>100</recordNumber>
</cd>
<cd>
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<year>1988</year>
<recordNumber>101</recordNumber>
</cd>
<cd>
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<year>1982</year>
<recordNumber>102</recordNumber>
</cd>
</catalog>
By the way:
- @michael。hor257k已经注意到,这个解决方案在大型输入XML文档上的性能很差,因为必须进行大量的比较。更具可扩展性的解决方案是使用分组机制(如XSLT 2.0中的
for-each-group
)。 - 永远不要相信www.w3schools.com上的任何输出。依赖可信赖的来源,如W3C。