views:

280

answers:

3

Hi

I'm using XSLT for displaying a ul menu containing li and a.

I want the following:

  1. Find the first li a element and add the .firstitem class.
  2. Find the last li a element and add the .lastitem class.
  3. Find the active li a element and add the .active class.
  4. Add an unique ID to each li a element. (I.e. URL friendly menu text as ID).

I've managed to make step 1-3 work. Except that when I try to add the classes, it actually replaces the other classes rather than adding to them.

Here's the code:

<li>
    <a>
        <!-- Add .firstitem class -->
        <xsl:if test="position() = 1">
            <xsl:attribute name="class">firstitem</xsl:attribute>
        </xsl:if>

        <!-- Add .lastitem class -->
        <xsl:if test="postition() = count(//Page)">
            <xsl:attribute name="class">lastitem</xsl:attribute>
        </xsl:if>

        <!-- Add .active class -->
        <xsl:if test="@Active='True'">
            <xsl:attribute name="class">active</xsl:attribute>
        </xsl:if>

        <!-- Add link URL -->
        <xsl:attribute name="href"><xsl:value-of select="@FriendlyHref" disable-output-escaping="yes"/></xsl:attribute>

        <!-- Add link text -->
        <xsl:value-of select="@MenuText" disable-output-escaping="yes"/>
    </a>
</li>

In realtity, the a element could contain all those three classes. But as is goes through the code, it replaces everything in the class attribute. How can I add the classes instead of replacing them?

And step number 4 on my list, is to get a unique ID, preferably based on @MenuText. I know there is a replace() function, but I can't get it to work and my editor says that replace() isn't a function.

The menu item text contains spaces, dashes and other symbols that are not valid for using in the id attribute. How can I replace those symbols?

A: 
Filburt
Why the downvote?
Filburt
Okay, i missed that the issue was only concerning the class attribute; i thought other attributes went missing.
Filburt
Thanks! That works like a charm!
rebellion
+6  A: 
<a>
       <xsl:attribute name="class">
            <!-- Add .firstitem class -->
            <xsl:if test="position() = 1">
                <xsl:text> firstitem</xsl:text>
            </xsl:if>
            <!-- Add .lastitem class -->
            <xsl:if test="postition() = count(//Page)">
                <xsl:text> lastitem</xsl:text>
            </xsl:if>

            <!-- Add .active class -->
            <xsl:if test="@Active='True'">
                <xsl:text> active</xsl:text>
           </xsl:if>
       </xsl:attribute>

        <!-- Add link URL -->
        <xsl:attribute name="href"><xsl:value-of select="@FriendlyHref" disable-output-escaping="yes"/></xsl:attribute>

        <!-- Add link text -->
        <xsl:value-of select="@MenuText" disable-output-escaping="yes"/>
    </a>

replace() is an XSLT2.0 function. When using XSLT1.0 you need a custom template to do most string manipulations.

Martijn Laarman
I can't believe I didn't knew this myself. So obvious when I see it now :P
rebellion
+4  A: 

I'm adding this to Martijn Laarman's answer, which covers your requirements 1-3 and has my vote:

To remove everything except a certain range of characters from a string with XSLT 1.0 (your 4th requirement), do the following.

<!-- declare at top level -->
<xsl:variable 
  name="validRange" 
  select="'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 
/>

<!-- later, within a template… -->
<xsl:attribute name="id">
  <xsl:value-of select="
    concat(
      'id_',
      translate(
        @MenuText, 
        translate(@MenuText, $validRange, ''),
        ''
      )
    )
  " />
</xsl:attribute>

The inner translate() removes any valid character from @MenuText, leaving only the invalid ones. These are fed to the outer translate(), which now can remove all invalid chars from the @MenuText, whatever they might be in this instance. Only the valid chars remain.

You can make a function out of it:

<xsl:template name="HtmlIdFromString">
  <xsl:param name="input" select="''" />
  <xsl:value-of select="
    concat('id_', translate( $input, translate($input, $validRange, ''), ''))
  " />
</xsl:template>

and call it like this:

<xsl:attribute name="id">
  <xsl:call-template name="HtmlIdFromString">
    <xsl:with-param name="input" select="@MenuText" />
  </xsl:call-template>
</xsl:attribute>
Tomalak
+1 missed requirement 4.
Martijn Laarman