hans.c hans.c - 3 months ago 9
HTML Question

How do I create a nested list using XSL transformation

I want to create an XSL file for the following transformation.

I have this XML file

<nodes>
<node url='url1' title='url1'>
<node url='url11' title='url11'>
<node url='url111' title='url111'/>
</node>
<node url='url11' title='url11'/>
<node url='url12' title='url12'/>
<node url='url13' title='url13'>
<node url='url131' title='url131'/>
<node url='url132' title='url132'/>
</node>
</node>
</node>
<node>
<node url='url2' title='url2'>
<node url='url21' title='url21'/></node>
</nodes>


Assuming, that url131 is selected, I want to create this HTML segment

<ul>
<li class='active'><a href='url1'>url1</a>
<ul>
<li><a href='url11'>url11</a></li>
<li><a href='url12'>url12</a></li>
<li class='active'><a href='url13'>url13</a>
<ul>
<li><span>url131</span></li>
<li><a href='url132'>url132<a></li>
</ul>
</li>
</li>
<li><a href='url2'>url2</a><li>
</ul>


In words: the selected element should be created as a span.
All parents should be marked as li.active.
All sibling of the selected element and its parents stay unmarked.
And everything should nested.

In the template I want to use param $self (that can be set from outside)
and apply template for the selected url:

<template match="nodes">
<xsl:param name='self'>url131</xsl:param>
<xsl:apply-template select="node()[@url=$self]</xsl:apply-template>
</template>


The template node must process 3 cases, to create LIs with SPANs or ANCORS with or without class .active.

<xls:template match="node">
<!-- todo: choose ... -->
</xsl:template>


But there is the tricky part (for me): will I need some kind of recursion, to go backwards in the tree.

//node[@url=self]/../. for the parent and //node[@url=self]/../../. for the grandparent and the same for their preceding- and following-siblings.

Or should I count the ancestores and use this number as level param. But vars and params can not be used for select, as far as i know.

Answer

In the template I want to use param $self (that can be set from outside)

If by "from outside" you mean from outside of the stylesheet, that's not possible. Only global (top-level) parameters can be passed to the stylesheet at runtime.

Consider the following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8" indent="yes"/>

<xsl:param name="selected-node-url">url142</xsl:param>

<xsl:template match="nodes">
    <ul>
        <xsl:apply-templates select="node"/>
    </ul>
</xsl:template>

<xsl:template match="node">
     <li>
        <xsl:if test="descendant::node/@url=$selected-node-url">
            <xsl:attribute name="class">active</xsl:attribute>
        </xsl:if>
        <xsl:choose>
            <xsl:when test="@url=$selected-node-url">
                <span><xsl:value-of select="@url"/></span>
            </xsl:when>
            <xsl:otherwise>
                <a href="{@url}"><xsl:value-of select="@url"/></a>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="node">
            <ul>
                <xsl:apply-templates select="node"/>
            </ul>
        </xsl:if>
     </li>
</xsl:template>

</xsl:stylesheet>

When applied to the following well-formed input:

XML

<nodes>
  <node url="url1" title="url1">
    <node url="url11" title="url11">
      <node url="url111" title="url111"/>
    </node>
    <node url="url12" title="url12"/>
    <node url="url13" title="url13"/>
    <node url="url14" title="url14">
      <node url="url141" title="url141"/>
      <node url="url142" title="url142"/>
    </node>
  </node>
  <node url="url2" title="url2">
    <node url="url21" title="url21"/>
  </node>
</nodes>

the result will be:

<ul>
   <li class="active"><a href="url1">url1</a><ul>
         <li><a href="url1">url11</a><ul>
               <li><a href="url1">url111</a></li>
            </ul>
         </li>
         <li><a href="url1">url12</a></li>
         <li><a href="url1">url13</a></li>
         <li class="active"><a href="url1">url14</a><ul>
               <li><a href="url1">url141</a></li>
               <li><span>url142</span></li>
            </ul>
         </li>
      </ul>
   </li>
   <li><a href="url1">url2</a><ul>
         <li><a href="url1">url21</a></li>
      </ul>
   </li>
</ul>
Comments