Как найти уровень определенного узла
Мой XML:
<menu>
<item id=1>
<item id=1.1>
<item id=1.1.1>
<item id=1.1.1.1>
<item id=1.1.1.2>
<item id=1.1.1.3>
</item>
</item>
<item id=1.2>
<item id=1.2.1>
<item id=1.2.1.1>
<item id=1.2.1.2>
<item id=1.2.1.3>
</item>
</item>
</item>
</menu>
И мой XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="menuId"/>
<xsl:template match="*">
<xsl:if test="descendant-or-self::*[@id=$menuId]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="item">
<xsl:if test="descendant-or-self::*[@id=$menuId] |
parent::*[@id=$menuId] |
preceding-sibling::*[@id=$menuId] |
following-sibling::*[@id=$menuId] |
preceding-sibling::*/child::*[@id=$menuId] |
following-sibling::*/child::*[@id=$menuId]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="item"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Я применяю некоторые правила, чтобы получить только определенный узел. Это нормально. Но теперь мне нужно получить только X (это число может варьироваться) выше уровней из выбранного menuId
Например. Если номер уровня X равен 2, а menuId равен 1.1.2.3, результатом будет:
<menu>
<item id=1.1>
<item id=1.1.1>
<item id=1.1.1.1>
<item id=1.1.1.2>
<item id=1.1.1.3>
</item>
</item>
<item id=1.2>
</item>
</menu>
Если номер уровня X равен 1, результат будет:
<menu>
<item id=1.1.1>
<item id=1.1.1.1>
<item id=1.1.1.2>
<item id=1.1.1.3>
</item>
</menu>
Чтобы получить текущий уровень, я бы использовал count(ancestor::*)
, Но я не знаю, как получить уровень узла [@id = $menuId]. Мне нужно включить что-то вроде count(ancestor::*) >= (count(ancestor::node[@id = $menuId]) - X)
внутри моего ЕСЛИ
Благодарю.
1 ответ
Решение
Я думаю, что наиболее эффективный способ приблизиться к этому - передать параметр подсчета вниз по apply-templates
цепь:
<xsl:variable name="targetDepth" select="count(//item[@id=$menuId]/ancestor::item)" />
<!-- I haven't thought this through in great detail, it might need a +1 -->
<xsl:template match="item">
<xsl:param name="depth" select="0" />
....
<xsl:if test=".... and ($targetDepth - $depth) <= $numLevels">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="item">
<xsl:with-param name="depth" select="$depth + 1" />
</xsl:apply-templates>
</xsl:copy>
</xsl:if>
</xsl:template>