Trying to understand what this does...

11 views
Skip to first unread message

Josh

unread,
Sep 16, 2011, 4:26:03 PM9/16/11
to XSLT
I am trying to determine exactly what is happening with the
"<xsl:apply-templates select=".|following-
sibling::childnode[position() &lt; $cellsPerRow]" mode="table"/>"
line.


My understanding is that it should send the next 5 (cellsPerRow) to
the "childnode" template for processing but I expect that my
understanding may be wrong, as it doesn't actually work. The output I
get is:

<table>
<tr>
<td>value1</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>value2</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<!-- repeat <tr> block for the number of childnodes found -->
</table>

I get that the FillerCells template is getting invoked but I don't
know why. If I comment out the call to FillerCells I get rid of the
"<td> </td>" But I thought that the code mentioned above should fill
in the <td>'s and only when it had nothing to put in them call
FillerCells.

Any help is appreciated greatly.

Josh

---------------------------------------------
Original XML File:
---------------------------------------------
<xml>
<parentnode>
<childnode>value1</childnode>
</parentnode>
<parentnode>
<childnode>value2</childnode>
</parentnode>
<!-- and so on for a couple of hundred repeats -->
</xml>
---------------------------------------------

XSL File:
--------------------------------------------
<xsl:template match="parentnode" mode="menu">
<xsl:variable name="cellsPerRow" select="5"/>
<xsl:for-each select="childnode[position() mod $cellsPerRow =
1]">
<tr>
<xsl:apply-templates select=".|following-
sibling::childnode[position() &lt; $cellsPerRow]" mode="table"/>
</tr>
</xsl:for-each>
</xsl:template>

<xsl:template match="childnode">
<!-- snipped table building code -->
<xsl:value-of select="."/>
<!-- snipped table building code -->

<xsl:if test="(position() = $apptotal) and (position() &lt;
$cellsPerRow)">
<xsl:call-template name="FillerCells">
<xsl:with-param name="cellCount"
select="$cellsPerRow - position()" />
</xsl:call-template>
</xsl:if>
</xsl:template>

<xsl:template name="FillerCells">
<xsl:param name="cellCount"/>
<td>&#160;</td>
<xsl:if test="$cellCount > 1">
<xsl:call-template name="FillerCells">
<xsl:with-param name="cellCount" select="$cellCount - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
--------------------------------------------

Christian Wahl

unread,
Sep 26, 2011, 8:09:01 AM9/26/11
to xs...@googlegroups.com
To answer your first question: <xsl:apply-templates select=".|following-sibling::childnode[position() &lt; $cellsPerRow]" mode="table"/> selects the element itself and following childnode elements (where position is less than $cellsPerRow). It seams that there are only one childnode element in each parentnode – is that right? – so the select only happens once. It uses the mode attribute to select a template with the same mode. Your <xsl:template match="childnode"> does not have this attribute – maybe it should?

What did you expect this code to generate? It seams that it could be don a little simpler, but there could be more use cases (?)

The template <xsl:template name="FillerCells"> is used as a kind of recursive function, repeating itself as long as "cellCount" is greater than 1. cellCount start value depends  on the number of childnode elements (if it works...).

Josh

unread,
Sep 26, 2011, 2:05:00 PM9/26/11
to XSLT
Thank you for the explanation, Christian. I had independently figured
that it wasn't what I needed. I was originally interpreting
"following::sibling" as being the equivalent node (childnode in my
example) of the the next parent node which I now know is incorrect.
Essentially I ended up getting around it using keys because what I
needed was a grouping of every 5 childnode's (I am building a table).
A more accurate representation of my XML source structure would have
been as follows.

<xml>
<parentnode>
<childnode>value1</childnode>
<anotherChildNode>value<anotherChildNode>
<yetAnotherChildNode>value<yetAnotherChildNode>
<...>
</parentnode>
<parentnode>
<childnode>value2</childnode>
<anotherChildNode>value<anotherChildNode>
<yetAnotherChildNode>value<yetAnotherChildNode>
<...>
</parentnode>
<!-- and so on for a couple of hundred repeats -->
</xml>

So by using keys I was able to extract all childnodes into a key and
then sort the output calling key recursively.

The ultimate goal, which I have now acheived, was to output a table
which was part of a menu system. So now I have a menu of all of my
childnodes, sorted alpahbetically, each letter being grouped into a
dynamically sized table without the need for JS. :)

Thank you again for your help Your explanation helped clear up some
other cobwebs I had about "following::sibling".

Josh
Reply all
Reply to author
Forward
0 new messages