使用 xslt 删除 xml 中的重复项

发布于 2024-11-25 08:23:32 字数 631 浏览 0 评论 0 原文

我需要删除以下 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>

有人可以帮忙吗?

I need to remove duplicates in the following 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>

Can anybody help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

怪我入戏太深 2024-12-02 08:23:32

使用标准分组解决方案可以轻松完成此任务。不要使用单个 select 语句来执行众所周知会导致性能问题的操作。

注意identity.xsl的引用只是将众所周知的身份转换模板。

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

This task can be easily achieved using standard grouping solutions. Do not use single select statements to do that which are well known to cause performance problems.

Note The reference to identity.xsl just include into the stylesheet the well known identity transformation template.

[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>
此岸叶落 2024-12-02 08:23:32

试试这个 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>

它将选择具有唯一 BookTypeBookNamebook。在您的示例中,结果应该是:

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

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

It will select books with unique BookType and BookName. In your sample result should be:

<book xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/">
        <BookType>Brand</BookType>
        <BookName>jon</BookName>
      </book>
还给你自由 2024-12-02 08:23:32

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

如何在 xslt 中使用 group by

如何使用 XSLT 输出重复元素?

You need to group them together using the Muenchian grouping method. Or the more specific grouping functions in xslt 2.0. Here are two relevant stack overflow questions:

How to use group by in xslt

How to output duplicate elements using XSLT?

落在眉间の轻吻 2024-12-02 08:23:32

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

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

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

现在,当您匹配 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])">

。换句话说,这个 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 以删除不必要的模板匹配。

If you interested in how this is achieved using Muenchian Grouping, which is a common technique in XSLT, you first need to define a 'key' to identify duplicate books within a row.

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

In this I am achieving this using a concatenated key of RowID, BookType and BookName. The key will contain a list of books all with that particular value of key. Do note the use of the # character as the joining character. If there is any chance of # appearing in your XML, you will need to pick another character (or string).

Now when you are matching on book elements, you can check for duplicates like so

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

In other words, is this book element the first element in our key.

Here is the full 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>

Also note the use of the identity transform so that other nodes can be copied without having to explicitly reference them. When this XSLT is applied to your input, the following output is generated:

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

EDIT: I have amended the XSLT to remove an unnecessary template match.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文