transform siblings nodes to imbricated nodes
I am experiencing issues with an XSLT. I have a set of sibling nodes( <level>
) inside <source>
, which I'd like to transform in an imbrication of nodes (i.e. each level would render inside its previous sibling).
XML INPUT
<?xml version="1.0"?>
<sources>
<source mode="manual" name="test1">
<level>blablabla Level1</level>
<level>this is the second level</level>
<level>this is the third level</level>
</source>
</sources>
Intended Output
the output I want is an imbricated html version of this (abridged, the imbrication is the thing here):
<form class="source manual">
source > <input value="test1" name="sourceName" type="text">
<!-- LEVEL #1 -->
<p class="deepnessIndicator">Deepn开发者_开发知识库ess: <strong>1</strong></p>
<div class="deepnessContainer">
<!-- LEVEL #2 -->
next-level:
<p class="deepnessIndicator">Deepness: <strong>2</strong></p>
<div class="deepnessContainer">
<!-- LEVEL #3 -->
next-level:
<p class="deepnessIndicator">Deepness: <strong>3</strong></p>
</div>
</div>
</form>
unfortunatly the XSL I composed fail, here the source (I tried to shorten but):
XSL
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="sources">
<xsl:apply-templates select="*" />
</xsl:template>
<!-- Main template here -->
<xsl:template match="source[@mode='manual']">
<form class="source manual">
source > <input type="text" name="sourceName" value="{@name}" />
<!-- Here's what I call first the recursion
the parameter is the # of the <level>
that should be processed -->
<xsl:call-template name="sourceLevelRecursion">
<xsl:with-param name="currentLevel">1</xsl:with-param>
</xsl:call-template>
</form>
</xsl:template>
<!-- Recursion template -->
<xsl:template name="sourceLevelRecursion">
<xsl:param name="currentLevel" />
<!-- this apply-templates should apply on only
one node because of the selector but it won't -->
<xsl:apply-templates mode="deepnessHeader" select="./level[$currentLevel]">
<xsl:with-param name="currentLevel"><xsl:value-of select="$currentLevel" /></xsl:with-param>
</xsl:apply-templates>
<xsl:if test="level[$currentLevel+1]">
<div class="deepnessContainer">
<!-- Recursion Call here -->
<xsl:call-template name="sourceLevelRecursion">
<xsl:with-param name="currentLevel"><xsl:value-of select="$currentLevel+1" /></xsl:with-param>
</xsl:call-template>
</div>
</xsl:if>
</xsl:template>
<xsl:template mode="deepnessHeader" match="level">
<xsl:param name="currentLevel" />
<p class="deepnessIndicator">Deepness: <strong><xsl:value-of select="$currentLevel" /></strong></p>
</xsl:template>
<xsl:template match="text()" />
Unfortunate output
the final erroneous output I obtain is:
<form class="source manual">
source > <input value="test1" name="sourceName" type="text">
<p class="deepnessIndicator">Deepness: <strong>1</strong></p>
<p class="deepnessIndicator">Deepness: <strong>1</strong></p>
<p class="deepnessIndicator">Deepness: <strong>1</strong></p>
<div class="deepnessContainer">
next-level:
<p class="deepnessIndicator">Deepness: <strong>2</strong></p>
<p class="deepnessIndicator">Deepness: <strong>2</strong></p>
<p class="deepnessIndicator">Deepness: <strong>2</strong></p>
<div class="deepnessContainer">
next-level:
<p class="deepnessIndicator">Deepness: <strong>3</strong></p>
<p class="deepnessIndicator">Deepness: <strong>3</strong></p>
<p class="deepnessIndicator">Deepness: <strong>3</strong></p>
</div>
</div>
</form>
As you can see, the apply:
<xsl:apply-templates mode="deepnessHeader" select="./level[$currentLevel]">
matched by
<xsl:template mode="deepnessHeader" match="level">
is matched thrice, one time per each <level>
in the source XML. But, the selector in apply-templates is supposed to select only one node isn't it ?
Use:
<xsl:apply-templates mode="deepnessHeader"
select="./level[position()=$currentLevel]">
XSLT 1.0 is "weakly typed". The XSLT processor doesn't know that the value contained by the $currentLevel
should be treated as an integer.
Therefore $currentLevel
is treated as a boolean -- as any non-integer expression inside a predicate should. However, if the actual value can be cast to an integer, then any integer value different than 0 is treated as true()
and the whole predicate is true()
so nothing is filtered out.
Remember:
In XPath 1.0 any Expr[someInteger]
, where someInteger
is an integer literal, is a shorthand for: Expr[position() = someInteger]
精彩评论