Это мой (смиренный) подход XSLT 1.0.Он не так элегантен, как другие, и во многих случаях может быть неудачным, но, в зависимости от вопроса, он выполняет свою работу и обладает определенной степенью настройки.
Проверка среди узловвыполняется по шаблону, построенному с использованием именованного шаблона: build-pattern
.Например, в вашем случае я сравниваю шаблон, построенный с использованием всех атрибутов value
узла;первый узел сравнивается с шаблоном типа v1v2v3
.Шаблон построен на элементах с именем Item
.Очевидно, этот шаблон можно изменить в соответствии с требованиями.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Node">
<xsl:variable name="current">
<xsl:call-template name="build-pattern">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:copy>
<xsl:copy-of select="@name"/>
<xsl:attribute name="matches">
<xsl:for-each select="../Node[not(generate-id()
= generate-id(current()))]">
<xsl:variable name="node">
<xsl:call-template name="build-pattern">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$current=$node">
<xsl:value-of select="@name"/>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template name="build-pattern">
<xsl:param name="node"/>
<xsl:for-each select="$node/Item">
<xsl:sort select="@value"/>
<xsl:value-of select="@value"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
При применении к этому входу:
<Document>
<Node name="n1">
<Item value="v1"/>
<Item value="v2"/>
<Item value="v3"/>
</Node>
<Node name="n2">
<Item value="p1"/>
<Item value="p2"/>
<Item value="p3"/>
</Node>
<Node name="n3">
<Item value="v3"/>
<Item value="v1"/>
<Item value="v2"/>
</Node>
<Node name="n4">
<Item value="p3"/>
<Item value="v1"/>
<Item value="v2"/>
</Node>
<Node name="n5">
<Item value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
</Node>
<Node name="n6">
<Item value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
<Node name="n7">
<Item value="v1"/>
<Item value="v1"/>
<Item value="v2"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
</Document>
Производит:
<Node name="n1" matches="n3n5"></Node>
<Node name="n2" matches=""></Node>
<Node name="n3" matches="n1n5"></Node>
<Node name="n4" matches=""></Node>
<Node name="n5" matches="n1n3"></Node>
<Node name="n6" matches=""></Node>
<Node name="n7" matches=""></Node>
Iобобщил вышеприведенное преобразование для поиска узлов с одинаковыми дочерними элементами:
- с любым именем
- в любом порядке
- с любым количеством атрибутов и любым именем
Нужно только заменить именованный шаблон build-pattern
следующими двумя:
<xsl:template name="build-pattern">
<xsl:param name="node"/>
<xsl:for-each select="$node/*">
<xsl:sort select="name()"/>
<xsl:sort select="@*[1]"/>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="attribute::*">
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="@*">
<xsl:value-of select="concat(name(),.)"/>
</xsl:template>
Например, когда новое преобразование применяется к следующему документу:
<Document>
<Node name="n1">
<Item value="v1" x="a2"/>
<foo value="v2" x="a1"/>
<Item value="v3"/>
</Node>
<Node name="n2">
<Item value="p1"/>
<Item value="p2"/>
<Item value="p3"/>
</Node>
<Node name="n3">
<Item value="v3"/>
<Item value="v1" x="a2"/>
<foo value="v2" x="a1"/>
</Node>
<Node name="n4">
<Item value="v3"/>
<Item value="v1"/>
<xxxx value="v2"/>
</Node>
<Node name="n5">
<xxxx value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
</Node>
<Node name="n6">
<Item value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
<Node name="n7">
<Item value="v1"/>
<Item value="v1"/>
<Item value="v2"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
</Document>
Производит:
<Node name="n1" matches="n3"/>
<Node name="n2" matches=""/>
<Node name="n3" matches="n1"/>
<Node name="n4" matches="n5"/>
<Node name="n5" matches="n4"/>
<Node name="n6" matches=""/>
<Node name="n7" matches=""/>