Ваша проблема в том, что вы используете оператор !=
для сравнения значения и набора узлов .
Это неправильно - всегда избегайте использования!=
оператор и всегда используйте функцию not()
и оператор =
, когда один из операндов в сравнении является набором узлов.
Ниже приведено правильное решение :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:for-each select="parent">
<xsl:for-each select="child[not(name = preceding::name)]">
<xsl:value-of select="concat(name, ' ')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к предоставленному документу XML :
<root>
<parent>
<child>
<name>John</name>
</child>
<child>
<name>Ben</name>
</child>
</parent>
<parent>
<child>
<name>John</name>
</child>
<child>
<name>Mark</name>
</child>
<child>
<name>Luke</name>
</child>
</parent>
</root>
желаемый, правильный результат получается :
John Ben Mark Luke
Объяснение : Вот как спецификация W3C XPath 1.0 определяет семантику оператора !=
:
"Если один объектсравниваемым является набор узлов, а другой является строкой, тогда сравнение будет истинным, если и только если в наборе узлов есть узел, так что результат выполнения сравнения со строковым значением узлаа другая строка истинна. "
Это означает, что
's' != node-set
всегда верно, если в node-set
есть только один узел, который не равен 's'
.
Это не та семантика, которая нужна.
С другой стороныside,
not('s' = node-set())
верно только в том случае, если в node-set
нет узла, равного 's'
.
Это именно то, что нужно для сравнения.
Обратите внимание : выбранная вами методика группировки O (N ^ 2) и должна использоваться только для очень небольших наборов значений, подлежащих дедупликации.Если требуется эффективность, во что бы то ни стало, используйте метод группировки Мюнхена (обсуждение или демонстрация этого выходит за рамки этого вопроса).