我刚刚开始学习XSLT,并且无法忽略重复的元素。
我一直在搜索Stack Overflow并且看到人们提出类似的问题。我尝试了一个小例子,看看我的文件出错了,并且能够忽略重复的元素。然而,当我有一种以上的元素时,似乎会出现问题。
例如:
File1.xml
<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<Main>
<Records>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
</Main>
merge2.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table border="1">
<tr>
<th>Type</th>
<th>Count</th>
</tr>
<xsl:for-each select="Main/Records/Record">
<xsl:if test ="not(preceding-sibling::Record(Description/text() = current()/Description/text()])">
<tr>
<td><xsl:value-of select="Description"/></td>
<td><xsl:value-of select="count(//Record[Description/text()=current()/Description/text()])"/></td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
这很好,并且给了我想要的结果。
Type Count
A 2
B 1
C 1
但是,如果我要添加另一个记录元素,它似乎一个接一个地处理它们,例如
<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<Main>
<Records>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
<Records>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
</Main>
这会产生以下结果。
Type Count
A 3
B 2
C 3
B 2
A 3
C 3
它似乎处理第一个记录实例,然后转到下一个。有没有办法让它能够消除两者之间的重复?
我已经尝试更改for-each以浏览每个Records实例,并尝试为它创建一个单独的模板,但是我似乎仍然遗漏了一些东西,因为我还没有设法让它工作。
非常感谢您的帮助。
答案 0 :(得分:4)
尝试使用preceding-sibling
中的preceding
替换xsl:if statement
。
您有正确的想法来制作测试,以便每个遇到的tr
值只发出一次Description
。但是,preceding-sibling
会停止通过父母的直接子女进行检查; preceding
在文档的前面继续检查,这是您希望避免Records
之间的重复。
Fyi,还有一个错字Record(
应该是Record[
。这是一个完整的,可操作的转型,包括这些改变:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table border="1">
<tr>
<th>Type</th>
<th>Count</th>
</tr>
<xsl:for-each select="Main/Records/Record">
<xsl:if test ="not(preceding::Record[Description/text() = current()/Description/text()])">
<tr>
<td><xsl:value-of select="Description"/></td>
<td><xsl:value-of select="count(//Record[Description/text()=current()/Description/text()])"/></td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
即使@kjhughes能够回答您的问题,但为了更有效的方法,您还需要使用Muenchain Method。
为此,您需要定义一个分组键
<xsl:key name="Record-by-Description" match="Record" use="Description"/>
然后使用该键对这些项目进行分组
<xsl:apply-templates select="Record[generate-id() = generate-id(key('Record-by-Description', Description)[1])]" mode="group"/>
然后使用该密钥仅计算那些特定项目
<xsl:value-of select="count(key('Record-by-Description', Description))"/>
此过程效率更高,每次都不需要导航整个结构。
所以,总而言之,当你采用这个XML
时<Main>
<Records>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
<Records>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
</Main>
并将此XSLT应用于它
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" />
<xsl:key name="Record-by-Description" match="Record" use="Description"/>
<xsl:template match="@* | node()">
<xsl:apply-templates select="@* | node()"/>
</xsl:template>
<xsl:template match="Main">
<table>
<tr>
<th>Type</th>
<th>Count</th>
</tr>
<xsl:apply-templates select="Records"/>
</table>
</xsl:template>
<xsl:template match="Records">
<xsl:apply-templates select="Record[generate-id() = generate-id(key('Record-by-Description', Description)[1])]" mode="group"/>
</xsl:template>
<xsl:template match="Record" mode="group">
<tr>
<td>
<xsl:value-of select="Description"/>
</td>
<td>
<xsl:value-of select="count(key('Record-by-Description', Description))"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
它产生此输出
<table>
<tr>
<th>Type</th>
<th>Count</th>
</tr>
<tr>
<td>A</td>
<td>3</td>
</tr>
<tr>
<td>B</td>
<td>2</td>
</tr>
<tr>
<td>C</td>
<td>3</td>
</tr>
</table>