使用xslt删除xml中的重复项

时间:2011-07-20 20:51:15

标签: xml xslt xpath distinct

我需要删除以下xml中的重复项:

<ListOfRowIDWithListOfBooks xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/">
  <RowIDWithListOfBooks>
    <Row_ID>ADOA-XssK</Row_ID>
    <ListOfBookInfo>
      <book>
        <BookType>Brand</BookType>
        <BookName>jon</BookName>
      </book>
      <book>
        <BookType>Brand</BookType>
        <BookName>jon</BookName>
      </book>
    </ListOfBookInfo>
  </RowIDWithListOfBooks>
</ListOfRowIDWithListOfBooks>

有人可以帮忙吗?

4 个答案:

答案 0 :(得分:6)

使用标准分组解决方案可以轻松实现此任务。不要使用单个select语句来做那些众所周知会导致性能问题的语句。

注意identity.xsl的引用只是在样式表中包含众所周知的identity transformation模板。

[XSLT 1.0]

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:key name="k-books" match="book" use="concat(BookType,'|',BookName)"/>

    <xsl:include href="identity.xsl"/>

    <xsl:template match="ListOfBookInfo">
        <ListOfBookInfo>
            <xsl:copy>
                <xsl:apply-templates select="book
                [generate-id()
                =generate-id(key('k-books',concat(BookType,'|',BookName))[1])]"/>
            </xsl:copy>
        </ListOfBookInfo>
    </xsl:template>

</xsl:stylesheet>

[XSLT 2.0]

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:include href="identity.xsl"/>

    <xsl:template match="ListOfBookInfo">
        <ListOfBookInfo>
            <xsl:for-each-group select="book" 
                group-by="concat(BookType,'|',BookName)">
                <xsl:apply-templates select="."/>
            </xsl:for-each-group>
        </ListOfBookInfo>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:2)

试试这个XSLT:

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

  <xsl:template match="/">
    <xsl:apply-templates select="//ListOfBookInfo/book[not(BookType = preceding-sibling::book/BookType
                         and BookName = preceding-sibling::book/BookName)]"/>
  </xsl:template>

  <xsl:template match="book">
    <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

它将选择具有唯一bookBookType的{​​{1}}个。在您的示例中,结果应为:

BookName

答案 2 :(得分:0)

您需要使用Muenchian分组方法将它们组合在一起。或xslt 2.0中更具体的分组功能。以下是两个相关的堆栈溢出问题:

How to use group by in xslt

How to output duplicate elements using XSLT?

答案 3 :(得分:0)

如果您对如何使用Muenchian Grouping(这是XSLT中的常用技术)实现这一目标感兴趣,首先需要定义一个“键”来识别行中的重复书籍。

<xsl:key 
   name="books"
   match="book"
   use="concat(concat(../../Row_ID, '#'), concat(concat(BookType, '#'), BookName))" />

在此我使用 RowID BookType BookName 的连锁键实现此目的。该密钥将包含所有具有该特定键值的书籍列表。请注意使用#字符作为连接字符。如果#出现在XML中,则需要选择另一个字符(或字符串)。

现在,当您在图书元素上进行匹配时,您可以检查是否有重复项

<xsl:variable 
  name="lookup"
  select="concat(concat(../../Row_ID, '#'), concat(concat(BookType, '#'), BookName))" />
<xsl:if test="generate-id() = generate-id(key('books', $lookup)[1])">

换句话说,这个 book 元素是我们键中的第一个元素。

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:output method="xml" indent="yes"/>
   <xsl:key 
      name="books"
      match="book"
      use="concat(concat(../../Row_ID, '#'), concat(concat(BookType, '#'), BookName))"/>

   <xsl:template match="book">
      <xsl:variable name="lookup" select="concat(concat(../../Row_ID, '#'), concat(concat(BookType, '#'), BookName))"/>
      <xsl:if test="generate-id() = generate-id(key('books', $lookup)[1])">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
         </xsl:copy>
      </xsl:if>
   </xsl:template>

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

还要注意使用身份转换,以便可以复制其他节点而无需显式引用它们。将此XSLT应用于输入时,将生成以下输出:

<RowIDWithListOfBooks xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/">
   <Row_ID>ADOA-XssK</Row_ID>
   <ListOfBookInfo>
      <book>
         <BookType>Brand</BookType>
         <BookName>jon</BookName>
      </book>
   </ListOfBookInfo>
</RowIDWithListOfBooks>

编辑:我修改了XSLT以删除不必要的模板匹配。