1

我有一个场景,其中 XML 文档包含一些重复的节点。我想摆脱所有这样的节点。请注意,这不是删除重复项”。我想完全删除那些多次出现的节点的所有条目。

前我的 XML

<ReadUserOBSResponse>
 <UserOBS>
  <OBSObjectId>1510</OBSObjectId>
  <UserObjectId>443</UserObjectId>
 </UserOBS>
 <UserOBS>
  <OBSObjectId>540</OBSObjectId>
  <UserObjectId>514</UserObjectId>
 </UserOBS>
 <UserOBS>
  <OBSObjectId>1521</OBSObjectId>
  <UserObjectId>514</UserObjectId>
 </UserOBS>
 <UserOBS>
  <OBSObjectId>547</OBSObjectId>
  <UserObjectId>544</UserObjectId>
 </UserOBS>
</ReadUserOBSResponse>

期望的输出:我想用 UserObjectId 514 删除两个条目

<ReadUserOBSResponse>
 <UserOBS>
  <OBSObjectId>1510</OBSObjectId>
  <UserObjectId>443</UserObjectId>
 </UserOBS>
 <UserOBS>
  <OBSObjectId>547</OBSObjectId>
  <UserObjectId>544</UserObjectId>
 </UserOBS>
</ReadUserOBSResponse>

我做了一些事情,但它不起作用。我的想法是用 UserObjectId 作为当前值来计算节点,把它放在 anxsl:if然后打印节点。但我不确定如何编写这个片段。

4

3 回答 3

2

这是一种使用键的非常有效(且简洁)的方法:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*" />
  <xsl:key name="kUOId" match="UserOBS" use="UserObjectId" />

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

  <xsl:template match="UserOBS[key('kUOId', UserObjectId)[2]]" />
</xsl:stylesheet>

在您的示例输入上运行时,结果是:

<ReadUserOBSResponse>
  <UserOBS>
    <OBSObjectId>1510</OBSObjectId>
    <UserObjectId>443</UserObjectId>
  </UserOBS>
  <UserOBS>
    <OBSObjectId>547</OBSObjectId>
    <UserObjectId>544</UserObjectId>
  </UserOBS>
</ReadUserOBSResponse>
于 2013-05-05T02:29:33.497 回答
2

这将满足您的需求。

它有一个元素模板,用于检查其父级中UserOBS是否恰好有一个具有相同值的子级。如果是这样,则将整个节点复制到输出。UserOBSUserObjectId

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:strip-space elements="*"/>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/ReadUserOBSResponse">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="UserOBS">
        <xsl:if test="count(../UserOBS[UserObjectId = current()/UserObjectId]) = 1">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="utf-8"?>
<ReadUserOBSResponse>
   <UserOBS>
      <OBSObjectId>1510</OBSObjectId>
      <UserObjectId>443</UserObjectId>
   </UserOBS>
   <UserOBS>
      <OBSObjectId>547</OBSObjectId>
      <UserObjectId>544</UserObjectId>
   </UserOBS>
</ReadUserOBSResponse>
于 2013-05-04T22:12:02.690 回答
1

在 XSLT 2.0 中要简单得多:

<xsl:for-each-group select="UserObs" group-by="UserObjectId">
  <xsl:copy-of select="current-group()[last()=1]"/>
</xsl:for-each-group>
于 2013-05-05T07:55:50.067 回答