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

时间:2011-05-09 12:47:21

标签: xml xslt

我有xml看起来像这样 -

<Root>
  <Fields>
    <Field name="abc" displayName="aaa" />
    <Field name="pqr" displayName="ppp" />
    <Field name="abc" displayName="aaa" />
    <Field name="xyz" displayName="zzz" />
  </Fields>
</Root>

我希望输出只包含那些具有重复name-displayName组合的元素,如果有的话 -

<Root>
      <Fields>
        <Field name="abc" displayName="aaa" />
        <Field name="abc" displayName="aaa" />
      </Fields>
</Root>

如何使用XSLT执行此操作?

2 个答案:

答案 0 :(得分:7)

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFieldByName" match="Field"
  use="concat(@name, '+', @displayName)"/>

 <xsl:template match=
  "Field[generate-id()
        =
         generate-id(key('kFieldByName',
                     concat(@name, '+', @displayName)
                     )[2])
        ]
  ">
     <xsl:copy-of select=
     "key('kFieldByName',concat(@name, '+', @displayName))"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<Root>
    <Fields>
        <Field name="abc" displayName="aaa" />
        <Field name="pqr" displayName="ppp" />
        <Field name="abc" displayName="aaa" />
        <Field name="xyz" displayName="zzz" />
    </Fields>
</Root>

产生想要的结果

<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>

<强>解释

  1. Muenchian grouping 使用复合键(在namedisplayName属性上)。

  2. 代码中唯一的模板匹配任何Field元素,该元素是相应组中的第二个元素。然后,在模板的主体内部输出整个组。

  3. Muenchian分组是 在XSLT 1.0中进行分组的有效方法。密钥用于提高效率。

  4. 另请参阅我对 this question 的回答。

  5. <强> II。 XSLT 2.0解决方案:

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="/">
         <xsl:for-each-group select="/*/*/Field"
              group-by="concat(@name, '+', @displayName)">
           <xsl:sequence select="current-group()[current-group()[2]]"/>
       </xsl:for-each-group>
     </xsl:template>
    </xsl:stylesheet>
    

    如果对提供的XML文档应用此转换(如上所示),则会再次生成所需的正确结果

    <Field name="abc" displayName="aaa"/>
    <Field name="abc" displayName="aaa"/>
    

    <强>解释

    1. 使用 <xsl:for-each-group>

    2. 使用 current-group() 功能。

答案 1 :(得分:1)

要查找重复项,您需要迭代Field元素,并为每个元素查找整个文档中匹配Field和{{1}的name元素集属性值。如果集合包含多个元素,则将该元素添加到输出中。

以下是实现此目的的模板示例:

displayName

在示例数据上执行此模板(包装在适当的XSLT文件中)会提供以下输出:

<xsl:template match="Field">
    <xsl:variable name="fieldName" select="@name" />
    <xsl:variable name="fieldDisplayName" select="@displayName" />
    <xsl:if test="count(//Field[@name=$fieldName and @displayName=$fieldDisplayName]) > 1">
        <xsl:copy-of select="."/>
    </xsl:if>
</xsl:template>