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>