使用XSLT和PerlXML::LibXSLT删除重复的XML元素

使用XSLT和PerlXML::LibXSLT删除重复的XML元素,xml,perl,xslt,Xml,Perl,Xslt,我有一个XML文件: 这是输入的内容。 这是输入的内容。 我正在尝试使用删除重复的: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d"> <xsl:output omit-xml-dec

我有一个XML文件:


这是输入的内容。
这是输入的内容。
我正在尝试使用删除重复的

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

对提供的XML文档应用此转换时

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

这是输入的内容。
这是输入的内容。
生成所需的正确结果

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

这是输入的内容。
这是输入的内容。
使用

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

对提供的XML文档应用此转换时

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

这是输入的内容。
这是输入的内容。
生成所需的正确结果

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" exclude-result-prefixes="d">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kIndexByValueTitle" match="d:index"
          use="concat(generate-id(..), '+', @d:value, '+', @d:title)"/>

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

  <xsl:template match=
   "d:index[not(generate-id()
               = generate-id(key('kIndexByValueTitle',
                                  concat(generate-id(..), '+', @d:value, '+', @d:title)
                                 )
                                  [1]))]" />
</xsl:stylesheet>
<d:dictionary xmlns="http://www.w3.org/1999/xhtml"
 xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
    <d:entry id="a" d:title="a">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="c" d:title="c"/>
        <d:index d:value="b" d:title="b"/>
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
    <d:entry id="b" d:title="b">
        <d:index d:value="a" d:title="a"/>
        <d:index d:value="b" d:title="b"/>
        <div>This is the content for entry.</div>
    </d:entry>
</d:dictionary>
<d:dictionary xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng" xmlns="http://www.w3.org/1999/xhtml">
   <d:entry id="a" d:title="a">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <d:index d:value="c" d:title="c"/>
      <div>This is the content for entry.</div>
   </d:entry>
   <d:entry id="b" d:title="b">
      <d:index d:value="a" d:title="a"/>
      <d:index d:value="b" d:title="b"/>
      <div>This is the content for entry.</div>
   </d:entry>
</d:dictionary>

这是输入的内容。
这是输入的内容。

有时直接使用编程库可能更容易。 使用XML::DT跟踪Perl脚本

#!/usr/bin/perl
use XML::DT;
my $filename = shift;
my %seen=();

my %handler=(
    'd:entry' => sub{ %seen=(); toxml },                     ## reset seen
    'd:index' => sub{ if ($seen{$v{"d:value"}}++){""    }    ## $v{id} -- attribute id 
                      else                       {toxml}},
);
print dt($filename, %handler);

与往常一样,如果未安装,
sudocpanxml::DT

有时直接使用编程库可能更容易。 使用XML::DT跟踪Perl脚本

#!/usr/bin/perl
use XML::DT;
my $filename = shift;
my %seen=();

my %handler=(
    'd:entry' => sub{ %seen=(); toxml },                     ## reset seen
    'd:index' => sub{ if ($seen{$v{"d:value"}}++){""    }    ## $v{id} -- attribute id 
                      else                       {toxml}},
);
print dt($filename, %handler);

通常,如果未安装,
sudo cpan XML::DT

xsl:for each group
需要XSLT 2.0。LibXSLT是XSLT1.0处理器。使用or.P.S。模板必须具有
匹配
名称
属性(或两者兼有)。刚刚尝试为
XSLT
2.0支持安装
XML::Saxon::XSLT2
,但失败了…为什么
Perl
库安装起来如此困难…:(这要归咎于你不太出色的OS X软件包管理器。在Linux上用XML::Saxon::XSLT2安装dist只花了我不到一分钟的时间。
xsl:for each group
需要XSLT 2.0。LibXSLT是XSLT 1.0处理器。使用或.P.S。模板必须具有
匹配
名称
属性(或两者兼有)。刚刚尝试为
XSLT
2.0支持安装
XML::Saxon::XSLT2
,但失败了…为什么
Perl
库安装起来如此困难…:(怪你的OS X软件包管理器不够出色。在Linux上用XML::Saxon::XSLT2安装dist花了我不到一分钟的时间。谢谢你的回答。@Dimitre Novatchev我应该提到每个条目都有自己独立的
@jonah_w,谢谢——你必须在问题中提供想要的结果。我编辑了答案并将其删除。)现在反映了您的最新需求。感谢您的提醒@Dimitre Novatchev,我刚刚更新了问题。因此我尝试了您的解决方案,非常棒。但有一件事,xml似乎被重新格式化为两行(失去了原始格式)。我想知道它是否可以在删除重复项的同时保留格式?@jonah_w,我不知道你所说的“原始格式”是什么意思。转换的结果具有问题中提供的XML文档格式。抱歉,我再次检查了。这是我在代码中犯的错误。生成的XML非常完美。:)谢谢你的回答。@Dimitre Novatchev我应该提到每个条目都有自己独立的
@jonah\u w,谢谢——你必须在问题中提供想要的结果。我编辑了答案,现在它反映了你的最新要求。谢谢你提醒@Dimitre Novatchev,我刚刚更新了问题。所以我尝试了你的解决方案在上,这真是太棒了。不过有一件事,xml似乎被重新格式化为两行(失去了原始格式)。我想知道它是否可以在删除重复项的同时保留格式?@jonah_w,我不知道你所说的“原始格式”是什么意思。转换的结果具有问题中提供的XML文档格式。抱歉,我再次检查。这是我在代码中犯的错误。生成的XML非常完美。:)感谢@JJoao我刚刚尝试了这种方法。生成的xml似乎删除了xml声明和命名空间。感谢@JJoao我刚刚尝试了这种方法。生成的xml似乎删除了xml声明和命名空间。