Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jamie 35 posts 87 karma points
    Oct 14, 2011 @ 04:59
    Jamie
    0

    Create alphbetical menu based on child nodes.

    I have created a 'glossary' Doc Type to hold a group of 'Glossary Term' child nodes.

    Glossary
    -- Apples
    -- Bannanas
    -- Cherries
    -- Eggplant
    -- Grapes

    In the template for the Glossary page I have an xslt that list the terms alphabetically. However I want a alpabet list 'menu' that when the letter is clicked it will jump down to the first word that starts with that letter. Any letter in this menu that is not used in the Glossary should be present but not a link eg

    using the small list above I'd like to see where [x] means a link'd letter

    [A][B][C] D [E] F  [G] H I ....Z

    However I have no idea how to accomplish this in XSLT.  I did serch the forums but the terms dictioanry and glossary don't yeild results that macth this sort of usage.  Any help/guidance would be apreciated.

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 7x admin c-trib
    Oct 14, 2011 @ 09:09
    Chriztian Steinmeier
    0

    Hi Jamie,

    Here's something to get you started:

    <xsl:param name="currentPage" />
    <xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
    
    <xsl:variable name="glossaryTerms" select="$siteRoot/Glossary/GlossaryTerm" />
    
    <!-- Create a <value> node for each letter -->
    <xsl:variable name="letters" select="umbraco.library:Split('ABCDEFGHIJKLMNOPQRSTUVWXYZ', '')" />
    
    <xsl:template match="/">
        <div>
            <xsl:apply-templates select="$siteRoot/Glossary" mode="index" />
    
            <xsl:apply-templates select="$siteRoot/Glossary" mode="list" />
        </div>
    </xsl:template>
    
    <xsl:template match="Glossary" mode="index">
        <p>
            <xsl:apply-templates select="$letters//value" />
        </p>
    </xsl:template>
    
    <xsl:template match="value">
        <xsl:variable name="matchingTerms" select="$glossaryTerms[starts-with(@nodeName, current())]" />
        <xsl:choose>
            <xsl:when test="$matchingTerms">
                <a href="#{$matchingTerms[1]/@urlName}">
                    <xsl:value-of select="." />
                </a>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="." />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="not(position() = last())"><xsl:text> </xsl:text></xsl:if>
    </xsl:template>
    
    
    <xsl:template match="Glossary" mode="list">
        <dl class="glossary">
            <xsl:apply-templates select="GlossaryTerm" />
        </dl>
    </xsl:template>
    
    <xsl:template match="GlossaryTerm">
        <dt id="{@urlName}"><xsl:value-of select="@nodeName" /></dt>
        <dd>
            Description: <xsl:value-of select="description" />
        </dd>
    </xsl:template>
    

    /Chriztian

  • Jamie 35 posts 87 karma points
    Oct 17, 2011 @ 07:11
    Jamie
    0

    Just getting back to look at this now.
    Thanks very much for your reply, I can kind of follow the logic however my knowledge on templates is very weak - so this should be a good learning experience for me. Unfortunatley a copy and paste of the code above give me an immediate error.

    Error occured

    System.FormatException: String must be exactly one character long. 
    at System.Convert.ToChar(String value, IFormatProvider provider) 
    at umbraco.library.Split(String StringToSplit, String Separator)

    I was able to solve this by adding a space in the split command.

    <xsl:variable name="letters" select="umbraco.library:Split('ABCDEFGHIJKLMNOPQRSTUVWXYZ', ' ')" />

    Then it all seems to run OK - except that the alpha menu at the top is not built.

    I'm guessing the split fails to 'do anything' with the space and therefor no matches are made on a

    letter-by-letter basis and I just get the whole unsplit array spat back out rather then matched links..

     

    Aslo - this makes the required solution more complicated ... this works for my sample list above
    - but what happens if multiple glossary items start with the same letter eg.

    -- Apple
    -- Apricot
    -- Bannanas
    -- Cherries
    -- Cucumbers
    -- Eggplant

    A link to the definition won't work will it? I'll need another template strucutre to insert letter links in the defintiion list

    A
    -- Apple  ... definition
    -- Apricot  ... definition
    B
    -- Bannanas  ... definition
    C
    -- Cherries  ... definition
    -- Cucumbers  ... definition
    E
    -- Eggplant  ... definition

    I'm going to look futher into the split command for just to get the linking in the alpha menu to work and then see how that effect the terms that share the same letter. I'll post any updates I do have.

  • Jamie 35 posts 87 karma points
    Oct 17, 2011 @ 07:28
    Jamie
    0

    Ha .. 30sec more thought and I could have saved a whole lot of typing .. I added spaces to the inital list to split by.
    umbraco.library:Split('A B C D E F G H I J K L M N O P Q R S T U V W X Y Z', ' ')

    The resultant list then links to the first definition item for each letter - perfect.

    The only thing this doesn't do that I could possibly want is the Alphabet breaks in the content list (as shown above). And an "other" matched area for things like non-alpha values eg numeric [0..9 $ %]

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 7x admin c-trib
    Oct 17, 2011 @ 09:58
    Chriztian Steinmeier
    0

    Hi Jamie,

    My bad about the character - I was actually using the tokenize() function in exslt.org (I develop on a Mac, so...) which accepts an empty character as the tokenizer - was pretty sure the Split() method worked the same way.

    For the Alphabet headers, you could just use the $letters//value nodes again - applying templates to each of them, rendering a header with the letter, and then applying templates to all the GlossaryTerm nodes that starts with that letter.

    For the "others" section, look for nodes which doesn't have a 1st 'letter' contained in the "alphabet" - something like:

    <xsl:apply-templates select="//GlossaryTerm[not(contains('ABCDEFGH...etc', substring(@nodeName, 1, 1)))]" />

    Let me know how you get along,

    /Chriztian

Please Sign in or register to post replies

Write your reply to:

Draft