Существует ли функция или оператор XPATH для сравнения глубины узлов?

#xpath #xslt-2.0

#xpath #xslt-2.0

Вопрос:

Пример:

 <ul>
    <li>item 1</li>
    <ul>
        <li>item 2</li>
        <li>item 3</li>
        <ul>
            <li>item 5</li> <!-- context node -->
        </ul>
    </ul>
    <li>item 6</li>
</ul>
 

Если li элемент с текстом item 5 является контекстным узлом, выражение following::* выдаст li элемент с текстом item 6 . Есть ли встроенный способ получить разницу в глубине этих узлов? т.е. если мы определили корень ul как имеющий глубину 0, то его дочерние элементы ( li пункт 1, ul , li пункт 6) будут иметь глубину 1 и так далее. li элемент 5 имеет глубину 3.

ancestor Ось может использоваться из обоих узлов, но интересно, есть ли другой способ. Другой возможностью может быть сохранение информации о состоянии при обходе дерева и если у родителя были следующие братья и сестры?

Комментарии:

1. Что не работает с использованием (количество?) ancestor оси? Что касается сохранения информации о состоянии при обходе дерева, в XSLT 3 вы могли бы сделать это с помощью аккумуляторов.

2. @MartinHonnen ancestor ось будет работать, мне было любопытно, есть ли более элегантное решение. Накопитель — хорошая функция для XSLT 3.

Ответ №1:

Вопрос помечен как XSLT 2, но, как вы упомянули обход дерева для сохранения информации о состоянии, возможно, стоит упомянуть накопитель XSLT 3, например

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
    
  <xsl:mode use-accumulators="depth"/>
    
  <xsl:accumulator name="depth" as="xs:integer" initial-value="0">
      <xsl:accumulator-rule match="/" select="0"/>
      <xsl:accumulator-rule match="*" select="$value   1"/>
      <xsl:accumulator-rule match="*" phase="end" select="$value - 1"/>
  </xsl:accumulator>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="*">
      <xsl:comment select="accumulator-before('depth'), count(ancestor-or-self::*)"/>
      <xsl:next-match/>
  </xsl:template>
  
</xsl:stylesheet>
 

https://xsltfiddle .liberty-development.net/ei5R4uS

Я знаю, что вы определили значение для корневого элемента как 0, но использование 0 для корневого узла / , а затем 1 в качестве глубины для его дочерних элементов кажется мне более разумным.