Вывод глубины текущего узла в иерархии
используя XSLT / XPATH 1.0, я хочу создать HTML, где на span
элемент указывает глубину в исходной иерархии XML.
например, с этим фрагментом XML:
<text>
<div type="Book" n="3">
<div type="Chapter" n="6">
<div type="Verse" n="12">
</div>
</div>
</div>
</text>
Я хочу этот HTML:
<span class="level1">Book 3</span>
<span class="level2">Chapter 6</span>
<span class="level3">Verse 12</span>
как глубоко эти div
элементы могут идти не известно априори. The div
s может быть книга - > глава. Они могут быть объем - > книга - > глава - > абзац - > строка.
Я не могу полагаться на значения @тип. Некоторые или все могут быть нулями.
3 ответов
это очень простое и короткое решение - нет рекурсии, нет параметров, нет xsl:element
, нет xsl:attribute
:
<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="div">
<span class="level{count(ancestor::*)}">
<xsl:value-of select="concat(@type, ' ', @n)"/>
</span>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к предоставленному XML-документу:
<text>
<div type="Book" n="3">
<div type="Chapter" n="6">
<div type="Verse" n="12"></div></div></div>
</text>
производится нужный, правильный результат:
<span class="level1">Book 3</span>
<span class="level2">Chapter 6</span>
<span class="level3">Verse 12</span>
объяснение: правильное использование шаблонов, AVT и
или без использования рекурсии-но ответ Дмитрия лучше, чем мой
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/text">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="//div">
<xsl:variable name="depth" select="count(ancestor::*)"/>
<xsl:if test="$depth > 0">
<xsl:element name="span">
<xsl:attribute name="class">
<xsl:value-of select="concat('level',$depth)"/>
</xsl:attribute>
<xsl:value-of select="concat(@type, ' ' , @n)"/>
</xsl:element>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
как обычно с XSL, используйте рекурсию.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/text">
<html>
<xsl:apply-templates>
<xsl:with-param name="level" select="1"/>
</xsl:apply-templates>
</html>
</xsl:template>
<xsl:template match="div">
<xsl:param name="level"/>
<span class="{concat('level',$level)}"><xsl:value-of select="@type"/> <xsl:value-of select="@n"/></span>
<xsl:apply-templates>
<xsl:with-param name="level" select="$level+1"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>