【问题标题】:XSLT Ignore duplicate elements across multiple filesXSLT 忽略跨多个文件的重复元素
【发布时间】:2013-09-23 08:20:15
【问题描述】:

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

索引.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 的单独模板并将“主”模板应用于不同的 XML 文件,还尝试使用 for-each 循环浏览不同的文件。

在被介绍给 Muenchian 方法之前,我使用带有“preceding”的 for-each 来检查重复节点,但是“preceding”似乎只在当前文档中搜索,并且无法找到有关在整个文档中使用它的信息多文档。

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

非常感谢您的帮助。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    基本上,每个文档都会构建密钥,因此基于直接密钥的 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(使用正确的命名空间),或者您需要使用 http://dpcarlisle.blogspot.de/2007/05/exslt-node-set-function.html 中的方法来确保 @ 987654326@函数已实现。

    【讨论】:

      【解决方案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>
      

      【讨论】:

      • 这可能是旧的,但谢谢你。我已经为此工作了几个小时。我不能使用exsl,这是一个非常简单的解决方案。非常适合我。
      猜你喜欢
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-11
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多