如何在考虑参数值的情况下从XML文件中删除重复元素

时间:2013-06-21 09:41:39

标签: xslt-1.0 xslt-2.0

我是XSLT的新手,在修改xml方面遇到了问题。

输入XML是:

<?xml version="1.0" encoding="UTF-8"?>
<xml>

   <dictionary>
      <label>A</label>
      <brand>top</brand>
      <color>black</color>
   </dictionary>

   <dictionary>
      <label>B</label>
      <brand>lower</brand>
      <color>brown</color>
   </dictionary>

   <dictionary>
      <label>A</label>
      <brand>lower</brand>
      <color>yello</color>
   </dictionary>

   <dictionary>
      <label>C</label>
      <brand>middle</brand>
      <color>orange</color>
   </dictionary>

   <dictionary>
      <label>B</label>
      <brand>top</brand>
      <color>blue</color>
   </dictionary>

   <dictionary>
      <label>D</label>
      <brand>mid</brand>
      <color>green</color>
   </dictionary>

   <dictionary>
      <label>A</label>
      <brand>mid</brand>
      <color>yello</color>
   </dictionary>

</xml>

它包含一些将A作为子元素之一的元素。我想删除包含重复项的字典节点。此外,虽然它删除了重复项,但它应该只删除包含!= lower

的重复节点

预期输出为:

<?xml version="1.0" encoding="UTF-8"?>
<xml>

   <dictionary>
      <label>B</label>
      <brand>lower</brand>
      <color>brown</color>
   </dictionary>

   <dictionary>
      <label>A</label>
      <brand>lower</brand>
      <color>yello</color>
   </dictionary>

   <dictionary>
      <label>C</label>
      <brand>middle</brand>
      <color>orange</color>
   </dictionary>

   <dictionary>
      <label>D</label>
      <brand>mid</brand>
      <color>green</color>
   </dictionary>

</xml>

在互联网上,我找到了一个基于元素值删除重复节点的xsl。删除重复节点的xsl是:

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

 <xsl:key name="LABEL" match="dictionary" use="label"/>

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

 <xsl:template match="dictionary[not(generate-id() = generate-id(key('LABEL', label)[1]))]"  />
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:0)

你的描述“当它删除重复项时,它应该只删除同样包含!= lower的重复节点”对我来说还不清楚,我试图用XSLT 2.0实现它,如下所示:

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

<xsl:output indent="yes"/>

<xsl:template match="xml">
  <xsl:copy>
    <xsl:for-each-group select="dictionary" group-by="label">
      <xsl:copy-of select="if (count(current-group()) eq 1)
                           then .
                           else current-group()[contains(brand, 'lower')]"/>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

转换输入

<?xml version="1.0" encoding="UTF-8"?>
<xml>

   <dictionary>
      <label>A</label>
      <brand>top</brand>
      <color>black</color>
   </dictionary>

   <dictionary>
      <label>B</label>
      <brand>lower</brand>
      <color>brown</color>
   </dictionary>

   <dictionary>
      <label>A</label>
      <brand>lower</brand>
      <color>yello</color>
   </dictionary>

   <dictionary>
      <label>C</label>
      <brand>middle</brand>
      <color>orange</color>
   </dictionary>

   <dictionary>
      <label>B</label>
      <brand>top</brand>
      <color>blue</color>
   </dictionary>

   <dictionary>
      <label>D</label>
      <brand>mid</brand>
      <color>green</color>
   </dictionary>

   <dictionary>
      <label>A</label>
      <brand>mid</brand>
      <color>yello</color>
   </dictionary>

</xml>

进入以下结果:

<xml>
   <dictionary>
      <label>A</label>
      <brand>lower</brand>
      <color>yello</color>
   </dictionary>
   <dictionary>
      <label>B</label>
      <brand>lower</brand>
      <color>brown</color>
   </dictionary>
   <dictionary>
      <label>C</label>
      <brand>middle</brand>
      <color>orange</color>
   </dictionary>
   <dictionary>
      <label>D</label>
      <brand>mid</brand>
      <color>green</color>
   </dictionary>
</xml>

dictionary子元素值和每个组的样式表组label元素输出组中的单个元素(如果只有一个)或输出组中的那些元素brand子元素值包含lower

根据评论中的要求,我使用Muenchian grouping而不是for-each-group添加了XSLT 1.0样式表:

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

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

<xsl:key name="by-label" match="dictionary" use="label"/>

<xsl:template match="xml">
  <xsl:copy>
    <xsl:for-each select="dictionary[generate-id() = generate-id(key('by-label', label)[1])]">
      <xsl:variable name="current-group" select="key('by-label', label)"/>
      <xsl:choose>
        <xsl:when test="count($current-group) = 1">
          <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$current-group[brand = 'lower']"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>