XSLT, проблема XPath только с уникальными дочерними узлами, когда неуникальные узлы вообще не выбраны - PullRequest
2 голосов
/ 01 декабря 2010
<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

Я пробовал:

<xsl:for-each select="parent">
  <xsl:for-each select="child[name != preceding::name]">
    <xsl:value-of select="name"/>
  </xsl:for-each>
</xsl:for-each>

Но я получаю:

Ben Mark Luke

?!

1 Ответ

7 голосов
/ 01 декабря 2010

Ваша проблема в том, что вы используете оператор != для сравнения значения и набора узлов .

Это неправильно - всегда избегайте использования!= оператор и всегда используйте функцию 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) и должна использоваться только для очень небольших наборов значений, подлежащих дедупликации.Если требуется эффективность, во что бы то ни стало, используйте метод группировки Мюнхена (обсуждение или демонстрация этого выходит за рамки этого вопроса).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...