XSLT 忽略重复元素 [英] XSLT Ignore duplicate elements

查看:28
本文介绍了XSLT 忽略重复元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆