XSL - remove the duplicate node but keep the original

天大地大妈咪最大 提交于 2020-01-03 03:47:22

问题


Need help in removing the duplicate node from the input xml using XSLT

This is how my XML looks like,

<?xml version="1.0"?>

<NodeA NodeAattr="123">

<NodeB NodeBattr="456"></NodeB>

<NodeC>
    <NodeD="ValueD">
       <NodeE Name="ValueABC">
          <NodeF Value="0"></NodeF >
       </NodeE >
       <NodeE Name="ValueABC">
          <NodeF Value="0"></NodeF >
       </NodeE>
  </NodeD>
</NodeC>
</NodeA>

My final output should look like

<NodeA NodeAattr="123">

<NodeB NodeBattr="456"></NodeB>

<NodeC>
    <NodeD="ValueD">
       <NodeE Name="ValueABC">
          <NodeF Value="0"></NodeF>
       </NodeE >
    </NodeD>
</NodeC>
</NodeA>

Here the Name attribute of Node E has duplicate values. Based on this attribute I need to eliminate the duplicate.

It would be really helpful if someone could help me with the XSLT required here to get the output. I can only use the XSLT 1.0


回答1:


If two <NodeE> elements are considered duplicates only if they have the same parent, this is probably the simplest solution:

Input

<?xml version="1.0"?>

<NodeA NodeAattr="123">

  <NodeB NodeBattr="456"></NodeB>

  <NodeC>
    <NodeD Name="ValueD">
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
    </NodeD>
    <!-- Added another <NodeD> element for demonstration -->
    <NodeD>
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
      <NodeE Name="ValueDEF">
        <NodeF Value="0"></NodeF>
      </NodeE>
    </NodeD>
  </NodeC>
</NodeA>

Stylesheet #1

<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"/>
  <xsl:strip-space elements="*"/>

  <!--
  Identity transform: copy elements and attributes from input file as is
  -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!--
  Drop <NodeE> elements with a preceding <NodeE> sibling that has the same
  @Name attribute value as the current element
  -->
  <xsl:template
    match="NodeE[preceding-sibling::NodeE[@Name = current()/@Name]]"/>

</xsl:stylesheet>

Output #1

<?xml version="1.0" encoding="utf-8"?>
<NodeA NodeAattr="123">
  <NodeB NodeBattr="456"/>
  <NodeC>
    <NodeD Name="ValueD">
      <NodeE Name="ValueABC">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
    <NodeD>
      <NodeE Name="ValueABC">
        <NodeF Value="0"/>
      </NodeE>
      <NodeE Name="ValueDEF">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
  </NodeC>
</NodeA>

On the other hand, if <NodeE> elements should be considered duplicates across the whole document, you can use Muenchian grouping:

Stylesheet #2

<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"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="kNode" match="NodeE" use="@Name"/>

  <!--
  Identity transform: copy elements and attributes from input file as is
  -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!--
  Use Muenchian grouping to apply unique NodeE elements.
  See http://www.jenitennison.com/xslt/grouping/muenchian.html
  -->
  <xsl:template match="NodeE[generate-id() = 
                       generate-id(key('kNode', @Name)[1])]">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Drop other <NodeE> elements -->
  <xsl:template match="NodeE"/>

</xsl:stylesheet>

Output #2

<?xml version="1.0" encoding="utf-8"?>
<NodeA NodeAattr="123">
  <NodeB NodeBattr="456"/>
  <NodeC>
    <NodeD Name="ValueD">
      <NodeE Name="ValueABC">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
    <NodeD>
      <NodeE Name="ValueDEF">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
  </NodeC>
</NodeA>



回答2:


Use "deep-euql" function to compare two item(). Check this one:

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

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

  <xsl:template match="NodeE">
    <xsl:choose>
      <xsl:when test="deep-equal(self::NodeE, following-sibling::NodeE)"/>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="* | @*"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>


来源:https://stackoverflow.com/questions/15924211/xsl-remove-the-duplicate-node-but-keep-the-original

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!