Xslt 如果一个数字重复,只显示一次

Xslt 如果一个数字重复,只显示一次,xslt,repeat,Xslt,Repeat,嗨,如果我有以下XML输入文件 <data> <group id= "1"> <phrase>Doc1</phrase> <document refid ="3"/> <document refid ="5"/> <document refid= "1"/> </group> <group id= "2"> <phrase>Doc2</phrase> <do

嗨,如果我有以下XML输入文件

<data>
<group id= "1">
<phrase>Doc1</phrase>
<document refid ="3"/>
<document refid ="5"/>
<document refid= "1"/>
</group>
<group id= "2">
 <phrase>Doc2</phrase>
<document refid ="2"/>
<document refid ="3"/>
<document refid= "6"/>
</group>
  <group id= "3">
 <phrase>Doc3</phrase>
<document refid ="2"/>
<document refid ="3"/>
<document refid= "4"/>
</group>
</data>

文件1
文档2
文件3
是否可以有一个输出来检查每个组,以查看文档“refid”编号是否未显示在以前的组中?例如,我希望我的输出为

<data>
 <group id= "1">
 <phrase>Doc1</phrase>
<document refid ="3"/>
<document refid ="5"/>
<document refid= "1"/>
</group>
<group id= "2">
 <phrase>Doc2</phrase>
<document refid ="2"/>
<document refid= "6"/>
</group>
  <group id= "3">
 <phrase>Doc3</phrase>
<document refid= "4"/>
</group>
</data>

文件1
文档2
文件3
我试图在XSLT1.0中实现这一点。 我希望这能清楚地解释这个问题。我非常感谢你的帮助。
谢谢你

这似乎很管用:

$cat style.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <!--
    This templates matches the document elements with a @refid that has already been used
    in on of the previous groups. They are simply ignored.
    -->
    <xsl:template match="document[../preceding-sibling::group/document/@refid = current()/@refid]" />


    <!--
    Everything else gets copied to the output.
    -->
    <xsl:template match="@*|*|text()">
        <xsl:copy>
            <xsl:apply-templates select="@*|*|text()" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
<?xml version="1.0"?>
<data>
    <group id="1">
        <document refid="3"/>
        <document refid="5"/>
        <document refid="1"/>
    </group>
    <group id="2">
        <document refid="2"/>

        <document refid="6"/>
    </group>
    <group id="3">


        <document refid="4"/>
    </group>
</data>
编辑:要将其合并到样式表中,请尝试将第49行中每个的
更改为:

<xsl:for-each select="document[not(../preceding-sibling::group/document/@refid = current()/@refid)]">

这里有一个简单有效的解决方案,使用键)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kDocById" match="document" use="@refid"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="group">
        <xsl:copy>
            <xsl:apply-templates select=
            "@*
            |
             node()[not(self::document)]
            |
             document
                  [generate-id()
                  =
                  generate-id(key('kDocById', @refid)[1])
                  ]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
<data>
   <group id="1">
      <phrase>Doc1</phrase>
      <document refid="3"/>
      <document refid="5"/>
      <document refid="1"/>
   </group>
   <group id="2">
      <phrase>Doc2</phrase>
      <document refid="2"/>
      <document refid="6"/>
   </group>
   <group id="3">
      <phrase>Doc3</phrase>
      <document refid="4"/>
   </group>
</data>

在提供的XML文档上应用此转换时(反映OP在评论中的最新改进):


文件1
文档2
文件3
生成所需的正确结果

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kDocById" match="document" use="@refid"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="group">
        <xsl:copy>
            <xsl:apply-templates select=
            "@*
            |
             node()[not(self::document)]
            |
             document
                  [generate-id()
                  =
                  generate-id(key('kDocById', @refid)[1])
                  ]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
<data>
   <group id="1">
      <phrase>Doc1</phrase>
      <document refid="3"/>
      <document refid="5"/>
      <document refid="1"/>
   </group>
   <group id="2">
      <phrase>Doc2</phrase>
      <document refid="2"/>
      <document refid="6"/>
   </group>
   <group id="3">
      <phrase>Doc3</phrase>
      <document refid="4"/>
   </group>
</data>

文件1
文档2
文件3

非常感谢您的帮助,但实际上我的XSLT文件中有最上面的代码,如果我尝试放置您为模板匹配提供的代码行,它会向我显示错误:元素必须仅在样式表的顶层使用。是否可以处理此错误?我不能从我的原始XSLT中删除它,因为我需要它来做其他事情。谢谢!有什么办法可以给你发邮件吗?它有点大,无法在我粘贴XSLT文件的注释部分正确显示它。我试着粘贴我的XML文件,但根本无法正常输出。我希望这有助于您理解我的问题您只是想让我添加到样式表的第49行?因为这不起作用:(你在回答中写的模板匹配如何。我是否需要处理它并将其粘贴到样式表中的某个位置?你可以使用我发布的作为独立样式表的整个样式表来预处理XML。但是如果你想将其合并到现有样式表中,那么你需要将第49行的
替换为标签。这是因为我的样式表中唯一重要的部分是XPath表达式。不要使用
version=“1.1”
。这是XSLT的一个过时版本。请参阅。@mzjn哦,是的,我有1.0。很抱歉,这是一个打字错误。尽管将
放置在$total for each循环中是徒劳的。这只会使您更难提取值(迫使您使用node-set()扩展名),然后
元素会被丢弃,因为从$total使用的只是text()节点,而不是元素。即使使用node-set(),也需要
节点集($total)/text()
,而不是
节点集($total/text())
-只能将
/text()
(子轴)应用于node-set()的结果,而不是结果树片段。我想提出一些积极的建议,但上面的输入XML与您发布的样式表所期望的输入太不匹配。例如,文档元素没有标题或@refid.Good question,+1。请参阅我的答案,以获得一个完整的解决方案,该解决方案简短、简单,并且是使用k的最有效的解决方案之一eys(明钦族分组)。天哪,非常感谢!!!这就成功了。我真的非常感谢你的时间和努力。非常感谢:)还有一个问题。如果我的输入更改为Doc1 Doc2格式,我如何让Doc1和Doc2也显示出来?您是否可以编辑发送给我的解决方案,以便我也可以打印Doc1和Doc2?谢谢!我真是感激不尽。太好了有你这样的优秀贡献者来帮助我们这些新手。非常感谢!:)@user807496:说“谢谢”的一种方式(这是SO的官方方式)就是接受最好的答案。为此,请单击答案旁边的复选标记。我很高兴我的回答有用。