XSL - удалить дубликат узла, но сохранить оригинал

Нужна помощь в удалении дубликата узла из входного XML с помощью XSLT

Вот так выглядит мой XML,

<?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>

Мой окончательный результат должен выглядеть следующим образом

<NodeA NodeAattr="123">

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

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

Здесь атрибут Name узла E имеет повторяющиеся значения. Основываясь на этом атрибуте, мне нужно удалить дубликаты.

Было бы очень полезно, если бы кто-то мог помочь мне с XSLT, требуемым здесь, чтобы получить вывод. Я могу использовать только XSLT 1.0

2 ответа

Если два <NodeE> элементы считаются дубликатами, только если они имеют одного и того же родителя, это, вероятно, самое простое решение:

вход

<?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>

Таблица стилей № 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>

Выход № 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>

С другой стороны, если <NodeE> элементы должны рассматриваться как дубликаты по всему документу, вы можете использовать мюнхенскую группировку:

Таблица стилей № 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>

Выход № 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>

Используйте функцию "deep-euql", чтобы сравнить два item(). Проверьте это:

<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>
Другие вопросы по тегам