Как выбрать узел XML с самым длинным дочерним значением #text узла в XPath? - PullRequest
5 голосов
/ 28 октября 2011

Я использовал XPath, чтобы выбрать узел с наибольшим значением целочисленного идентификатора, прежде чем использовать этот запрос:

//somenode[not(@id <= preceding::somenode/@id) and not(@id <= following::somenode/@id)]

Я надеялся, что смогу сделать что-то подобное:

//entry[not(string-length(child::text()) <= string-length(preceding::entry/child::text())) and not(string-length(child::text()) <= string-length(following::entry/child::text()))]

Но он возвращает группу узлов вместо одного.

Пример XML:

<xml>
  <entry>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</entry>
  <entry>Nam dignissim mi a massa mattis rutrum eu eget mauris.</entry>
  <entry>Ut at diam a sem scelerisque pretium nec pulvinar purus.</entry>
  <entry>Nunc in nisi nec dolor accumsan suscipit vel a quam.</entry>
  <entry>Nunc suscipit lobortis arcu, nec adipiscing libero bibendum nec.</entry>
  <entry>Aenean eget ipsum et nunc eleifend scelerisque.</entry>
  <entry>In eu magna et diam volutpat molestie.</entry>
  <entry>In volutpat luctus mi, eu laoreet orci dictum vel.</entry>
  <entry>In mattis mi nec magna sodales eu bibendum felis aliquet.</entry>
<!-- etc for 800 more lines or so -->
  <entry>Duis auctor felis id neque gravida ut auctor ipsum ullamcorper.</entry>
  <entry>Sed vel tortor mauris, et aliquet tellus.</entry>
</xml>

Тест XPath: http://chris.photobooks.com/xml/default.htm?state=1o

1 Ответ

2 голосов
/ 28 октября 2011

Требуемые элементы не могут быть выбраны с помощью одного выражения XPath 1.0 , поскольку в XPath 1.0 невозможно применить функцию ко всем выбранным узлам (string-length(someNodeSet) применяется только кпервый узел этого набора узлов).Другая причина в том, что в XPath 1.0 невозможно присвоить имена и ссылаться на переменные диапазона.

В XPath 2.0 это тривиально :

/*/entry[not(string-length(.) &lt; /*/entry/string-length(.))]

.все entry элементы, длина строкового значения которых является максимальной.

/*/entry[not(string-length(.) &lt; /*/entry/string-length(.))] [1]

Вышеуказанный элемент выбирает первый (в порядке документа) такой entry элемент.

Проверка на основе XSLT 2.0 :

Это преобразование:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="/">
  <xsl:sequence select=
   "/*/entry[not(string-length(.) &lt; /*/entry/string-length(.))]"/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<xml>
  <entry>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</entry>
  <entry>Nam dignissim mi a massa mattis rutrum eu eget mauris.</entry>
  <entry>Ut at diam a sem scelerisque pretium nec pulvinar purus.</entry>
  <entry>Nunc in nisi nec dolor accumsan suscipit vel a quam.</entry>
  <entry>Nunc suscipit lobortis arcu, nec adipiscing libero bibendum nec.</entry>
  <entry>Aenean eget ipsum et nunc eleifend scelerisque.</entry>
  <entry>In eu magna et diam volutpat molestie.</entry>
  <entry>In volutpat luctus mi, eu laoreet orci dictum vel.</entry>
  <entry>In mattis mi nec magna sodales eu bibendum felis aliquet.</entry>
<!-- etc for 800 more lines or so -->
  <entry>Duis auctor felis id neque gravida ut auctor ipsum ullamcorper.</entry>
  <entry>Sed vel tortor mauris, et aliquet tellus.</entry>
</xml>

выбирает элементы entry (в данном случае только один) с максимальной длиной строки и выводит выбранные элементы :

<entry>Nunc suscipit lobortis arcu, nec adipiscing libero bibendum nec.</entry>
...