Search

I'm trying to build an efficient navigation-utility with two navigation levels. I have 4 pages (first-level navigation) and 4 sections (each contains entries which are the second-level).

My problem: The <xsl:with-param>-part does not work. It outputs the right path, but the for-each does not work. When I enter the correct path directly in the for-each instead of using the param, it does work.

Any idea how to fix this? Or is it not possible to create a dynamic for-each?

snippet from my XML:

<navigation>
    <page handle="startseite">
      <name>Startseite</name>
      <types>
        <type>hidden</type>
      </types>
    </page>
    <page handle="profil">
      <name>Profil</name>
    </page>
    <page handle="projekte">
      <name>Projekte</name>
    </page>
    <page handle="lehre">
      <name>Lehre</name>
    </page>
    <page handle="kontakt">
      <name>Kontakt</name>
    </page>
</navigation>

  <navigation-profil>
    <section id="13" handle="profil">Profil</section>
    <entry id="117">
      <titel handle="promotion">Promotion</titel>
    </entry>
    <entry id="118">
      <titel handle="lehre">Lehre</titel>
    </entry>
    <entry id="119">
      <titel handle="kommunikation">Kommunikation</titel>
    </entry>
  </navigation-profil>

  <navigation-projekte>
      ...
  </navigation-projekte>

   ...

snippet from my XSLT

<xsl:template match="page">

        <li class="rubrik">
        <a href="{$root}/{@handle}/" class="rubrik">
                <xsl:value-of select="name"/>
        </a>
        <xsl:call-template name="subnavigation">
            <xsl:with-param name="match-path" select="concat('/data/navigation-', @handle, '/entry')"/>
        </xsl:call-template>
        </li>

</xsl:template>

<xsl:template name="subnavigation">
<ul>
    <xsl:for-each select="$match-path">
        <li>
            <a href="{$root}/{titel/@handle}/">
                <xsl:value-of select="titel"/>
            </a>
            <xsl:if test="@handle = $current-page">
                <xsl:attribute name="class">active</xsl:attribute>
            </xsl:if>
        </li>
    </xsl:for-each>
</ul>
</xsl:template>

So, the root of your problem is that $match-path is a string because you're using concat(), which outputs a string. You can't use a string as an xpath query. I have run into the problem of dynamically generating an xpath query before, and there is no simple solution. You might be able to concat your 'navigation-???' element into a string, then use that directly in the XPath. If that doesn't work, you could possibly test for the name of that element.

so something like this <xsl:with-param name="match-path" select="/data/$navigation-name/entry"/>

or this <xsl:with-param name="match-path" select="/data/*[name()='$navigation-name']/entry"/>

not sure about the name() function, but I think that's right

I was thinking about doing something similar. The trick is to make sure that the XPath expression can be properly evaluated as a node-set. As soon as you turn the expression into a string, it can no longer be evaluated as a node-set and you'll get a "wrong type" error.

So, ashooner was on the right track, but I think some of the details were a little off. A parameter cannot be used as part of the XPath expression:

/data/$navigation-name/entry

And the name() function is trying to match a string, rather than a parameter, because of the single quotes, and I think the name() function needs a specific node to return the element name:

name()='$navigation-name'

Try something like this:

<xsl:param name="navigation-entries" select="/data/*[name(.) = concat('navigation",'-',$navigation-name)]/entry"/>

Then you have a valid XPath expression that you can use with the xsl:for-each instruction:

<xsl:for-each select="$navigation-entries">
  <xsl:value-of select="blah"/>
</xsl:for-each>

Thanks a bunch, guys! Bauhouse, you were right. The funny part is, that I have to put this whole /data/*[...]/entry-thing into the subnavigation-template. It does not work in the match="page"-part.

This is the whole working XSLT-Template

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="navigation">
    <xsl:apply-templates select="page[not(types/type = 'hidden') and not(types/type = 'admin')]"/>
    <xsl:if test="/data/events/login-info/@logged-in = 'true'">
        <li><a href="{$root}/drafts/">Drafts</a></li>
        <li><a href="{$root}/symphony/">Admin</a></li>
        <li><a href="?debug">Debug</a></li>
    </xsl:if>
</xsl:template>

<xsl:template match="page">
    <ul id="nav-{@handle}">
        <li class="rubrik">
            <xsl:if test="@handle = $current-page">
                <xsl:attribute name="id">subactive</xsl:attribute>
            </xsl:if>
            <a href="{$root}/{@handle}/" class="rubrik">
                <xsl:value-of select="name"/>
            </a>
            <xsl:call-template name="subnavigation">
                <xsl:with-param name="match-name" select="@handle"/>
            </xsl:call-template>
        </li>
    </ul>
</xsl:template>

<xsl:template name="subnavigation">

<xsl:param name="match-path" select="/data/*[name(.) = concat('navigation-',$match-name)]/entry" />
<xsl:if test="count($match-path) != 0">
    <ul>
        <xsl:for-each select="$match-path">
            <li>
            <!-- $content-handle is the URL Parameter -->
                <xsl:if test="$content-handle = titel/@handle">
                    <xsl:attribute name="class">active</xsl:attribute>
                </xsl:if>
                <a href="{$root}/{$match-name}/{titel/@handle}/">
                    <xsl:value-of select="titel"/>
                </a>
            </li>
        </xsl:for-each>
    </ul>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

It looks like I had errors of my own. I see you fixed up the syntax I suggested for the concat function. Glad that's working for you.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details