识别每个循环中的对象并使用相同的数字消除对象

时间:2013-11-12 20:47:03

标签: xml xslt

这是我的输入

<someAccounts>
    <Account>
           <type>ABC</type>
           <number>123456789</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
       <Account>
           <type>BBC</type>
           <number>234567890</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
       <Account>
           <type>CBC</type>
           <number>345678900</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
        <Account>
           <type>DBC</type>
           <number>999999999</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
       <Account>
           <type>FBC</type>
           <number>999999999</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
  </someAccounts>

这里有2个帐号对象,它们具有相同的编号。我想要消除具有相同数字(不只是一个)的帐户对象。基本上这应该是我的输出

<someAccounts>
 <Account>
           <type>ABC</type>
           <number>123456789</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
       <Account>
           <type>BBC</type>
           <number>234567890</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
       <Account>
           <type>CBC</type>
           <number>345678900</number>               
           <productCode>011</productCode>
           <packageCode>022</packageCode>
        </Account>
  </someAccounts>

我尝试使用此

        <xsl:for-each>
          <xsl:copy-of select="someAccounts/Account[number != current()/number]"/>
        </xsl:for-each>

这只能消除重复的一个,但我需要删除这两个帐户,我该如何实现。请帮忙

3 个答案:

答案 0 :(得分:2)

首先,您可能会在XSLT identity transform的基础上构建,以复制XML中的现有元素

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

这意味着您只需要编写一个模板来忽略具有重复数字元素的帐户元素。如果您想检查带有重复数字元素的帐户元素,那么您可以定义一个键来查找它们

<xsl:key name="account" match="Account" use="number" />

有了这个,你只需要这个简单的模板来忽略重复

<xsl:template match="Account[key('account', number)[2]]" />    

即。如果至少有两个帐户元素具有相同的数字,请忽略帐户元素。

试试这个XSLT

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

   <!-- Key to look up Account elements by their number -->
   <xsl:key name="account" match="Account" use="number" />

   <!-- Ignore Account elements for which there are at least two with the same number -->
   <xsl:template match="Account[key('account', number)[2]]" />    

    <!-- Copy all other elements as-is -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

以下XSLT 1.0生成所需的输出。它使用显式for-eachif结构。该密钥有助于查找由相同数字定义的帐户集。只复制一组大小。

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

  <!-- create key to find the accounts given by a number -->
  <xsl:key name="number_key" match="Account" use="number/text()"/>

  <xsl:template match="/someAccounts">

    <xsl:copy>

      <xsl:for-each select="Account">

        <!-- key('number_key', ./number) returns a set of accounts with a given number -->
        <!-- the next if only copies if the this set has size = 1 -->

        <xsl:if test="count(key('number_key', ./number)) = 1">
          <xsl:copy-of select="."/>
        </xsl:if>

      </xsl:for-each>

    </xsl:copy>

  </xsl:template>

</xsl:stylesheet>

在XSLT 2.0中,for-each-group构造可用于确定组大小。方法的结构保持不变:

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

  <xsl:template match="/someAccounts">

    <xsl:copy>

      <xsl:for-each-group select="Account" group-by="number">

        <!-- current-group() returns a set of accounts with a given number -->
        <!-- the next if only copies if the this set has size = 1 -->

        <xsl:if test="count(current-group()) = 1">
          <xsl:copy-of select="current-group()[1]"/>
        </xsl:if>

      </xsl:for-each-group>

    </xsl:copy>

  </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:0)

这是另一个更简单的解决方案,基于这样的假设:number元素的值在任何先前的 Account中发生,那么Account不是复制过来。基本上,这是使用这一个额外模板的身份转换:

<xsl:template match="Account[./number=preceding-sibling::*/number]"/>

在上面,我们匹配任何Account元素,该元素的数字也出现在前一个兄弟中。如果是这样,什么也不做。其他一切都被复制了。

以下是完整代码:

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

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

    <xsl:template match="Account[./number=preceding-sibling::*/number]"/>

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

</xsl:stylesheet>

当应用于OP中的输入XMl时,它给出:

<someAccounts>
    <Account>
        <type>ABC</type>
        <number>123456789</number>
        <productCode>011</productCode>
        <packageCode>022</packageCode>
    </Account>
    <Account>
        <type>BBC</type>
        <number>234567890</number>
        <productCode>011</productCode>
        <packageCode>022</packageCode>
    </Account>
    <Account>
        <type>CBC</type>
        <number>345678900</number>
        <productCode>011</productCode>
        <packageCode>022</packageCode>
    </Account>
    <Account>
        <type>DBC</type>
        <number>999999999</number>
        <productCode>011</productCode>
        <packageCode>022</packageCode>
    </Account>
</someAccounts>