XSLT忽略多个文件中的重复元素

时间:2013-09-23 08:20:16

标签: xml xslt

我最近问过一个关于如何忽略多个元素的问题,并且对于使用“前面”和Muenchian方法得到了一些很好的回答。但是我想知道是否可以使用索引xml文件在多个文件中执行此操作。

INDEX.XML

<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<list>
    <entry name="File1.xml" />
    <entry name="File2.xml" />
</list>

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>

Merge2.xsl

  <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>

这在一个文件上工作正常,并为我提供了生成一个表所需的结果,只显示了唯一的项目并添加了计数。但是,在浏览多个文件的index.xml时,我无法生成所需的结果。

我尝试使用一个针对index.xml的单独模板,并将'Main'模板应用于不同的XML文件,并尝试使用for-each循环遍历不同的文件。

在介绍Muenchian方法之前,我使用for-each和'previous'来检查重复的节点,但是'previous'似乎只搜索当前文档并且无法找到有关使用它的信息多文件。

这些方法中的任何一种都能够在多个文档中搜索重复的元素文本吗?

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

基本上每个文档都构建了密钥,因此基于Muenchian分组的直接密钥不允许您识别和删除多个文档中的重复项。

然而,您可以先将两个文档合并为一个,然后将Muenchian分组应用于合并文档。

如果要在一个样式表中合并和分组,则需要使用exsl:node-set或类似内容:

  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">

  <xsl:output method="xml" indent="yes" />
  <xsl:key name="Record-by-Description" match="Record" use="Description"/>

  <xsl:template match="/">
    <xsl:variable name="merged-rtf">
      <Main>
        <xsl:copy-of select="document(list/entry/@name)/Main/Records"/>
      </Main>
    </xsl:variable>
    <xsl:apply-templates select="exsl:node-set($merged-rtf)/Main"/>
   </xsl:template>

  <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>

现在,您将index.xml作为主输入文档传递给样式表。

如果要在IE浏览器中进行此转换,则需要将exsl:node-set替换为Microsoft ms:node-set(使用正确的命名空间),或者需要使用{{3}中的方法确保exsl:node-set函数已实现。

答案 1 :(得分:2)

如果可以的话,虽然已经用Muenchian方法回答了这个问题,但是12年来我一直在邮件列表(例如http://www.sourceware.org/ml/xsl-list/2001-10/msg00933.html)和课堂上推广基于变量的XSLT 1.0分组方法。

基于变量的分组方法允许您在一次传递中对多个文件进行分组。使用基于变量的方法进行子组也非常简单。无论您可以解决的是什么人口都可以放入变量,然后分组方法适用于该变量。

我希望下面的说明性成绩单有助于...您可以看到样式表非常紧凑,您不需要两次通过而且您不需要使用任何扩展名。

数据:

t:\ftemp>type multi.xml 
<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<list>
    <entry name="File1.xml" />
    <entry name="File2.xml" />
</list>

t:\ftemp>type File1.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>

结果:

t:\ftemp>call xslt multi.xml multi.xsl 
<?xml version="1.0" encoding="utf-8"?>
<table>
   <tr>
      <th>Type</th>
      <th>Count</th>
   </tr>
   <tr>
      <td>A</td>
      <td>6</td>
   </tr>
   <tr>
      <td>B</td>
      <td>4</td>
   </tr>
   <tr>
      <td>C</td>
      <td>6</td>
   </tr>
</table>

样式表:

t:\ftemp>type multi.xsl 
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="list">
    <table>
      <tr>
        <th>Type</th>
        <th>Count</th>
      </tr>
      <xsl:variable name="records"
                          select="document(entry/@name)/Main/Records/Record"/>

      <xsl:for-each select="$records">
        <xsl:if test="
                  generate-id(.)=
                  generate-id($records[Description=current()/Description][1])">
          <tr>
            <td>
              <xsl:value-of select="Description"/>
            </td>
            <td>
              <xsl:value-of
                  select="count($records[Description=current()/Description])"/>
            </td>
          </tr>
        </xsl:if>
      </xsl:for-each>
    </table>
  </xsl:template>

  </xsl:stylesheet>