1

我是 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>
4

1 回答 1

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 分组添加了一个 XSLT 1.0 样式表,而不是for-each-group

<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>
于 2013-06-21T10:15:44.333 回答