Как определить уровень вложенности в XPath?

В следующем примере я хотел бы определить «уровень вложенности» узла с выражением XPath (2.0). Этот «уровень вложенности» будет числом последовательных потомков, например. если "span/span/span" существует, это будет 3. Ожидаемые уровни вложенности указаны в комментариях:

<?xml version="1.0" encoding="UTF-8"?>
<text>
    <div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget
        dolor. Aenean massa.
        <span><!--nesting level:2-->Cum sociis natoque penatibus et magnis dis parturient montes,
            nascetur ridiculus mus.
            <span><!--nesting levels:1-->Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.
                <span><!--nesting levels:0-->Nulla consequat massa quis enim.</span>
            </span>
            <span><!--nesting levels:0-->Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.</span>
            In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
        </span>
        <span><!--nesting levels:0-->Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus
            elementum semper nisi.
        </span>
        <span><!--nesting levels:0-->Aenean vulputate eleifend tellus. Aenean leo ligula,
            porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
            quis, feugiat a, tellus.
        </span>
    </div>
    <div>Phasellus viverra nulla ut metus varius laoreet.
        <span><!--nesting levels:0-->Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue.
        </span>
        <span><!--nesting levels:2-->Curabitur ullamcorper ultricies nisi.
            <span><!--nesting levels:0-->Nam eget dui.</span>
            Etiam rhoncus.
            <span><!--nesting levels:1-->Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet
                adipiscing sem neque sed ipsum.
                <span><!--nesting levels:0-->Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem.</span>
                <span><!--nesting levels:0-->Maecenas nec odio et ante tincidunt tempus.</span>
                Donec vitae sapien ut libero venenatis faucibus.
                <span><!--nesting levels:0-->Nullam quis ante.</span>
            </span>
            Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet
            nibh.
        </span>
        Donec sodales sagittis magna.
    </div>
</text>

Теперь я попробовал count(descendant::span)), но, очевидно, это также будет включать всех братьев и сестер и во многих случаях даст неправильный результат. Я также пробовал count(descendant::span[1])) и count(descendant::span[position() = 1])), которые также давали ошибочные результаты. Я еще не мог понять, как исключить количество братьев и сестер из общего числа. Любая подсказка приветствуется.


person friedemann_bach    schedule 15.03.2017    source источник


Ответы (1)


В XSLT я получаю правильные значения с выражением

            max(
              for $leaf in descendant-or-self::span[not(span)]
              return count($leaf/ancestor-or-self::span except ancestor-or-self::span)
            )

например с таблицей стилей

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="span">
        <xsl:copy>
            <xsl:attribute name="nesting-level"
                select=" 
                max(
                  for $leaf in descendant-or-self::span[not(span)]
                  return count($leaf/ancestor-or-self::span except ancestor-or-self::span)
                )"/>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

я получаю вывод

<?xml version="1.0" encoding="UTF-8"?><text>
    <div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget
        dolor. Aenean massa.
        <span nesting-level="2"><!--nesting level:2-->Cum sociis natoque penatibus et magnis dis parturient montes,
            nascetur ridiculus mus.
            <span nesting-level="1"><!--nesting levels:1-->Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.
                <span nesting-level="0"><!--nesting levels:0-->Nulla consequat massa quis enim.</span>
            </span>
            <span nesting-level="0"><!--nesting levels:0-->Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.</span>
            In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
        </span>
        <span nesting-level="0"><!--nesting levels:0-->Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus
            elementum semper nisi.
        </span>
        <span nesting-level="0"><!--nesting levels:0-->Aenean vulputate eleifend tellus. Aenean leo ligula,
            porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
            quis, feugiat a, tellus.
        </span>
    </div>
    <div>Phasellus viverra nulla ut metus varius laoreet.
        <span nesting-level="0"><!--nesting levels:0-->Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue.
        </span>
        <span nesting-level="2"><!--nesting levels:2-->Curabitur ullamcorper ultricies nisi.
            <span nesting-level="0"><!--nesting levels:0-->Nam eget dui.</span>
            Etiam rhoncus.
            <span nesting-level="1"><!--nesting levels:1-->Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet
                adipiscing sem neque sed ipsum.
                <span nesting-level="0"><!--nesting levels:0-->Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem.</span>
                <span nesting-level="0"><!--nesting levels:0-->Maecenas nec odio et ante tincidunt tempus.</span>
                Donec vitae sapien ut libero venenatis faucibus.
                <span nesting-level="0"><!--nesting levels:0-->Nullam quis ante.</span>
            </span>
            Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet
            nibh.
        </span>
        Donec sodales sagittis magna.
    </div>
</text>
person Martin Honnen    schedule 15.03.2017
comment
Большое спасибо! Это впечатляет. Я не ожидал, что решение будет таким сложным. Надо будет позже проверить - извините за задержку! - person friedemann_bach; 19.03.2017
comment
Это может дать правильный ответ для данного примера, но он не пытается удовлетворить требование о том, что элементы span в пути должны быть последовательными: он сообщит об уровне вложенности 3 для span/div/div/span/span - person Michael Kay; 31.03.2017
comment
Чтобы исправить это, я думаю, вы должны квалифицировать descendant::span с помощью предиката, такого как [every $a in ancestor::* except $origin/ancestor::* satisfies $a/self::span], где $origin привязан к самому внешнему узлу контекста. - person Michael Kay; 31.03.2017
comment
Спасибо, Михаил, за ваш комментарий. Хотя решения Мартина достаточно для моего варианта использования, ваше замечание было бы важно учитывать в других сценариях. - person friedemann_bach; 06.04.2017