Вот пример:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:functx="http://www.functx.com"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs functx">
<xsl:output indent="yes"/>
<xsl:function name="functx:index-of-node" as="xs:integer*">
<xsl:param name="nodes" as="node()*"/>
<xsl:param name="nodeToFind" as="node()"/>
<xsl:sequence select="
for $seq in (1 to count($nodes))
return $seq[$nodes[$seq] is $nodeToFind]
"/>
</xsl:function>
<xsl:function name="mf:eliminate-deep-equal-duplicates" as="node()*">
<xsl:param name="nodes"/>
<xsl:sequence
select="for $node in $nodes
return $node[not(some $preceding-node in $nodes[position() lt functx:index-of-node($nodes, $node)] satisfies deep-equal($node, $preceding-node))]"/>
</xsl:function>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="coll">
<xsl:copy>
<xsl:for-each-group select="rootNode" group-by="Header/code">
<xsl:copy>
<xsl:apply-templates select="Header,
mf:eliminate-deep-equal-duplicates(current-group()/(* except (Header, children))),
children"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="rootNode/children">
<xsl:copy>
<xsl:apply-templates select="mf:eliminate-deep-equal-duplicates(current-group()/children/*)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Что касается объяснения: Опубликованная таблица стилей имеют три шаблона, первые из которых шаблон тождественного преобразования (что позволяет нам копию элементы, которые мы хотим скопировать, выполнив apply-templates
на них в других шаблонах), второй соответствующий coll
элементов, чтобы создать их мелкую копию, а затем применить текстовую книгу for-each-group
на элементах rootNode
, сгруппировав их по Header/code
, как вы просили. Внутри for-each-group
, для каждой группы xsl:copy
создает rootNode
и заполнит его путем обработки Header
элемента первого элемента в группе (таким образом мы получаем только один Header
результирующий элемент в каждой группе), детей, за исключением Header
и children
каждого пункта в группе, в которой нет предыдущего элемента deep-equals
в группе и элемента children
первого элемента в группе, чтобы обеспечить, чтобы каждая группа получала дочерний элемент children
. В шаблоне для этого элемента нам нужно затем убедиться, что мы обрабатываем всех великих детей в текущей группе, у которых нет дубликата deep-equal
перед ними.
Я отредактировал длинное выражение в функции mf:eliminate-deep-equal-duplicates
, он выбирает эти узлы в последовательности узлов, для которых ни один предшествующий узел в той же последовательности не равен deep-equal
.
Решение использует функцию http://www.xsltfunctions.com/xsl/functx_index-of-node.html библиотеки functx, которая дает нам индекс узла в последовательности.
Как Владимир Нестеровского отметил в комментарии, функция mf:eliminate-deep-equal-duplicates
также может быть реализована без использования functx functx:index-of-node
:
<xsl:function name="mf:eliminate-deep-equal-duplicates" as="node()*">
<xsl:param name="nodes"/>
<xsl:sequence
select="for $i in (1 to count($nodes)),
$node in $nodes[$i]
return $node[not(some $preceding-node in $nodes[position() lt $i] satisfies deep-equal($node, $preceding-node))]"/>
</xsl:function>
Спасибо! Я не уверен, зачем нужен второй шаблон? Не могли бы вы объяснить две ключевые строки шаблона запроса, поскольку у меня возникают проблемы с тем, как они работают? –
Я отредактировал ответ с исправленной версией и некоторым объяснением. Оказалось, что предыдущее предложение имело правильный подход, но не совсем правильное осуществление, я думаю. Я тестировал несколько выборочных данных с дублирующими элементами, и новое решение устраняет их. –
Awesome спасибо много Мартин, объяснение помогает много –