如何使用XSLT删除重复的XML节点

时间:2008-12-10 11:00:07

标签: xml xslt

我有一个非常长的XML文件,比如

<Root>
   <ele1>
      <child1>context1</child1>
      <child2>test1</child2>
      <child1>context1</child1>
   </ele1>

   <ele2>
      <child1>context2</child1>
      <child2>test2</child2>
      <child1>context2</child1>
   </ele2>
   <ele3>...........<elen>
</Root>

现在我想使用xslt删除每个<child1>中的所有第二个<ele>,是否可能? 结果是这样的:

<Root>
   <ele1>
      <child1>context1</child1>
      <child2>test1</child2>
   </ele1>

   <ele2>
      <child1>context2</child1>
      <child2>test2</child2>
   </ele2>
       <ele3>...........<elen>
</Root>

谢谢你,BR

阿伦

3 个答案:

答案 0 :(得分:4)

这个问题需要更详细的答案,而不仅仅是指向一个好的Muenchian Grouping来源。

原因是所需的分组需要识别“ele [SomeString]”元素及其父元素的所有子元素的名称。 Such grouping需要定义一个由两个唯一源唯一定义的密钥,通常是通过连接。

此转化

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

 <xsl:key name="kElByName" match="*"
      use="concat(generate-id(..), '+',name())"/>

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

    <xsl:template match="*[starts-with(name(), 'ele')]">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select=
         "*[generate-id()
           =
            generate-id(key('kElByName',
                        concat(generate-id(..), '+',name())
                        )[1])
            ]"
         />
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

应用于此XML文档时

<Root>
    <ele1>
        <child1>context1</child1>
        <child2>test1</child2>
        <child1>context1</child1>
    </ele1>
    <ele2>
        <child1>context2</child1>
        <child2>test2</child2>
        <child1>context2</child1>
    </ele2>
    <ele3>
        <child2>context2</child2>
        <child2>test2</child2>
        <child1>context1</child1>
    </ele3>
</Root>

产生想要的结果

<Root>
    <ele1>
        <child1>context1</child1>
        <child2>test1</child2>
    </ele1>
    <ele2>
        <child1>context2</child1>
        <child2>test2</child2>
    </ele2>
    <ele3>
        <child2>context2</child2>
        <child1>context1</child1>
    </ele3>
</Root>

答案 1 :(得分:2)

如果OP提供的XML代表他/她的问题(并且应删除每个<child1>元素中的 2nd <ele*>,那么Muenchian Grouping不是必要的:

<强> XSLT:

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

  <!-- Identity Template: copies everything as-is -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Remove the 2nd <child1> element from each <ele*> element -->
  <xsl:template match="*[starts-with(name(), 'ele')]/child1[2]" />

</xsl:stylesheet>

针对提供的XML运行时:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <ele1>
    <child1>context1</child1>
    <child2>test1</child2>
    <child1>context1</child1>
  </ele1>
  <ele2>
    <child1>context2</child1>
    <child2>test2</child2>
    <child1>context2</child1>
  </ele2>
</Root>

...产生了所需的结果:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <ele1>
    <child1>context1</child1>
    <child2>test1</child2>
  </ele1>
  <ele2>
    <child1>context2</child1>
    <child2>test2</child2>
  </ele2>
</Root>

答案 2 :(得分:-1)

您的xml和问题有点不清楚,但您正在寻找的通常称为Muenchian Grouping方法 - 这是另一种要求不同节点的方式。使用适当的键可以非常有效地完成。