XSLT 忽略重复元素 [英] XSLT Ignore duplicate elements
问题描述
我刚刚开始学习 XSLT,在忽略重复元素时遇到问题.
我一直在搜索 Stack Overflow,看到有人问过类似的问题.我尝试了一个小例子来查看我的文件哪里出错了,并且能够忽略重复的元素.然而,当我有不止一种类型的元素时,我的问题似乎出现了.
例如:
文件 1.xml
merge2.xsl
<xsl:output method="html"/><xsl:template match="/"><表格边框=1"><tr><th>类型</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></xsl:模板></xsl:stylesheet>
这很好用并且给了我想要的结果.
类型计数A2乙 11
但是,如果我要添加另一个 Records 元素,它似乎会一个接一个地处理这两个元素,例如
这将产生以下结果.
类型计数一个 3乙 23乙 2一个 33
它似乎处理了第一个 Records 实例,然后移动到下一个实例.有什么办法可以消除两者之间的重复项吗?
我尝试更改 for-each 以遍历 Records 的每个实例,并尝试为其创建单独的模板,但是我似乎仍然缺少一些东西,因为我没有设法让它工作.>
非常感谢您的帮助.
尝试用 xsl:if 语句中的
preceding
替换 preceding-sibling
代码>.
你有正确的想法来制作你的测试,这样你就每个遇到的 Description
值只发出一次 tr
.但是,preceding-sibling
停止通过父项的直接子项进行回查;preceding
继续检查文档中较早的部分,这是您想要避免跨 Records
重复的地方.
仅供参考,还有一个拼写错误,其中 Record(
应该是 Record[
.这是一个完整的操作转换,包括这些更改:
<xsl:output method="html"/><xsl:template match="/"><表格边框=1"><tr><th>类型</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></xsl:模板></xsl:stylesheet>
I have just started to learn XSLT and am having trouble ignoring duplicated elements.
I have been searching through Stack Overflow and have seen people ask similar questions. I tried a small example to see where I was going wrong on my file, and was able to ignore duplicated elements. However the problem for me seems to arise when I have more than one type of an element.
For Example:
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>
This works fine and gives me the desired results.
Type Count
A 2
B 1
C 1
However if I were to add another Records element it seems to process the two one after another e.g.
<?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>
This would produce the following.
Type Count
A 3
B 2
C 3
B 2
A 3
C 3
Where it seems to process the first instance of Records, then move onto the next. Is there any way of making it so that it would remove duplicates across the two?
I have tried changing the for-each to go through each instance of Records, and have tried to create a separate template for it, however I still seem to be missing something as I have not managed to get it working.
Many thanks for any help.
Try replacing preceding-sibling
with just preceding
in your xsl:if statement
.
You had the right idea to craft your test so that you only emit a tr
once per encountered Description
value. However, preceding-sibling
stops checking back through immediate children of the parent; preceding
continues checking earlier in the document, which is what you want to avoid the duplication across Records
.
Fyi, there's also a typo where Record(
should be Record[
. Here's a complete, operational transformation including those changes:
<?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>
这篇关于XSLT 忽略重复元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!