Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

A-Z List links after each letter of the alphabet 1

Status
Not open for further replies.

73pixieGirl

Programmer
Oct 3, 2006
65
US
Hello,
I'm very new to XML and I've inherited a website built entirely in XML (lucky me). I have a request to build an A-Z index that will list our inhouse resources alphabetically. So when a user clicks on the letter M, the page jumps down to a list of resources that begin with M. But the requestor would also like for the index to be displayed after each letter grouping of the alphabet (a simple Back to the Top link won't do for some reason). Can anyone tell me what steps I need to take to build a page like this? I've read many XML books online and hardcopy, and can understand the logistics, but actually creating the code is a different story. I know how to build the xml file that contains the names of the resources, that's the easy part! But styling it per the requestor's request has got me stumped.
TIA!
 
This method of building a web site is actually not designed for its ease of learning, but for its effectiveness in separating content from presentation. As such, it does a pretty good job. However, there are few tutorials. O'Reilly has a book or two. Do you own these?

Without knowing much about Cocoon, it seems to me that the sitemap.xmap describes is a pipeline process that says that the source of the data is an XML document, and then a series of transforms are processed on that XML document before it is finally processed into HTML for display. Again, just guessing , the input document for final2.xsl is the output document from the preceeding transform.

A stylesheet has only one input document unless it expressly uses the document() function to (temporarily) gather input from another input document.

Tom Morrison
 
From what I've read about Cocoon, you are correct! I've got XML for Dummies, Beginning XML, XSLT 2nd Edition, and the Cocoon Developer's Handbook. I've also read an XML book online (can't think of the name right now). At this point I read the same thing over and over and I can grasp an understanding of it, but it's the multiple files and what's pulling what from where and how is what drives me batty. I'm still working on re-working my page based on the code you listed above...stay tuned! Thank you for all of your help!!
 
I'm back... :(
I'm trying to incorporate your solution into my .xsl page, by piece-mealing it to get a better understanding of what it's doing. When I incorporate the following lines of code into my page, nothing is being printed out but at least my page loads with the header:

<xsl:template match="//resource">
<xsl:variable name="allResources">
<xsl:for-each select="resource/name">
<xsl:copy-of select="document(.)/*"/>
</xsl:for-each>
</xsl:variable>
</xsl:template>

But when I add the following, I get "An Error Occurred" page:

<xsl:variable name="allSorted">
<xsl:for-each select="$allResources/resource">
<xsl:sort select="name"/>
<sorted-entry><letter><xsl:value-of select="translate(substring(name,1,1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></letter><xsl:copy-of select="."/></sorted-entry>
</xsl:for-each>
</xsl:variable>

I interpret this piece of code as:
1. create variable
2. for each resource, sort on the name node
3. not sure what the sorted-entry does, but then it's converting the first character (letter) of each name node to uppercase.

Do you know why this piece would give me an error?
I left the template match="//resource" as is b/c that's the parent node. Also, what does the following code snippet do/say?
<xsl:copy-of select="document(.)/*"/>
TIA!!!
 
[tt]<xsl:copy-of select="document(.)/*"/>[/tt] is attempting to open an input file and make a copy of that document's root node into the output tree. It clearly is not applicable in your situation. My example presumed multiple input documents, but your situation does not seem to have multiple input documents.

In order to be able to assist you further, please understand that you simply must show an input document (even if you have to cleanse it of proprietary information -- we care about its structure). If this document is already an output of the Cocoon system, then it should not be too difficult to show us the structure. If the document is an intermediate step in a Cocoon pipeline, then you might need to create another entry in the sitemap to XML serialize the results of the preceding step.

In the example I provided earlier, the first variable was being used as a place to gather all the resource names and descriptions into one nodeset. If you have a single input document, as your XSLT implies, then you already have that nodeset and the first variable is unnecessary. The second variable is used to create a nodeset conveniently sorted for the desired output.

not sure what the sorted-entry does
It creates a [tt]<sorted-entry> [/tt] element in the nodeset. The [tt]$allSorted [/tt]variable contains a nodeset that has the following structure:
Code:
[i]<implicit root>[/i]
  <sorted-entry>
    <letter>A</letter>
    <name>AAA</name
    <description>A description of AAA</description>
  </sorted-entry>
  <sorted-entry>
    <letter>A</letter>
    <name>ABC</name
    <description>A description of ABC</description>
  </sorted-entry>
  ...
[i]</implicit root>[/i]

So, a look at the input document structure, please...

Tom Morrison
 
Ok, here's an example of the input document (resource_verizon.xml)...all 170 documents have the same structure:

<resource filename="resource_verizon">
<name>Verizon Super Pages</name>
<description>Browser accessibility to the White and Yellow Pages for the areas of the Maryland suburbs, greater Norther Virginia, and Washington D.C.</description>
<url low="" high=""/>
<provider>Verizon Directories Corporation</provider>
<coverage_dates>2001-2003</coverage_dates>
<status value="" expiredate=""/>
</resource>

...and the code I sent in the "2 Feb 07 7:19" post is used to build the output page which has each resource name (the name is a hyperlink) and the description.

Is this of any help? [ponder]
 
We are back to the need for an XML document which describes all the input documents. If you are going to collect information from 170 XML documents, you need a single XML document that contains the URLs( pathnames) of the 170 documents. This is what my example in the 1 Feb 07 17:36 post teaches.

the code I sent in the "2 Feb 07 7:19" post
is valid only if all 170 resources are contained in a single input document.

So, you are not showing me the input document yet, I think...

Tom Morrison
 
Can you hear me screaming? [upsidedown]
I discovered more files in the sitemap, but I'm afraid this is just getting more and more complicated. I'll add the new stuff, but feel free to throw your hands up and tell me it's too much to deal with!

the sitemap.xmap:
<!-- generate an xml list of filenames from given directory using Directory Generator e.g. /library/internal/dirlist/content/resource -->
<map:match pattern="internal/dirlist/**">
<map:generate type="directory" src="{1}">
<!-- only retrieve xml files. -->
<map:parameter name="include" value="xml$"/>
</map:generate>
<map:serialize type="xml"/>
</map:match>

also:
<!-- generate complete xml list of resource elements from Directory Generator output -->
<map:match pattern="internal/resources.xml">
<map:generate src="cocoon://library/internal/dirlist/content/resource" label="res"/>
<map:transform src="xsl/getxmlfromfilenames.xsl" label="inres2">
<map:parameter name="dir" value="content/resource/"/>
<map:parameter name="enclosing_element" value="resources"/>
</map:transform>
<map:serialize type="xml"/>
</map:match>

and here's the getxmlfromfilenames.xsl code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl=" version="1.0" xmlns:dir=" >
<!-- retrieves and concatenates the xml from files in a Cocoon Directory Generator -->

<xsl:param name="dir"/>
<xsl:param name="enclosing_element"/>

<xsl:template match="/">
<xsl:element name="{$enclosing_element}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>

<xsl:template match="dir:directory/dir:file">
<xsl:variable name="filename" select="@name"/>
<xsl:variable name="fullfilename" select="concat('../', $dir, $filename)"/>
<xsl:variable name="stuff" select="document($fullfilename)"/>
<xsl:copy-of select="$stuff"/>
</xsl:template>
</xsl:stylesheet>

then the sitemap.xmap file has this:
<!-- all resources, alpha sorted -->
<map:match pattern="internal/alpha-res.xml">
<map:generate src="cocoon://library/internal/resources.xml"/>
<map:transform src="xsl/alpha_sort_resources.xsl"/>
<map:serialize type="xml"/>
</map:match>

and here's the alpha_sort_resources.xsl file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl=" version="1.0">

<xsl:template match="//resources">
<resources>
<xsl:apply-templates select="resource">
<xsl:sort select="name"/>
</xsl:apply-templates>
</resources>
</xsl:template>

<xsl:template match="resource">
<xsl:copy-of select="."/><p/>
</xsl:template>
</xsl:stylesheet>

and finally...this is what I've been following in the sitemap.xmap file:
<!-- list ALL Resources alphabetically -->
<map:match pattern="resources_alpha">
<map:generate src="template/template_3pane.xml"/>
<map:transform src="xsl/merge_to_template.xsl">
<map:parameter name="mapping_file_name" value="mapping_3pane_resources_alpha.xml"/>
</map:transform>
<map:transform src="xsl/process_myincludes.xsl" label="al2"/>
<map:transform type="cinclude" label="alpha"/>
<map:transform src="xsl/resources_alpha.xsl"/>
<map:serialize type="html"/>
</map:match>

with the resources_alpha.xsl file being what I posted in my 2 Feb post. [dazed]

Does it all add up now?
 
Code:
<!-- generate complete xml list of resource elements from Directory Generator output -->
<map:match pattern="internal/resources.xml">
   <map:generate src="cocoon://library/internal/dirlist/content/resource" label="res"/>
   <map:transform src="xsl/getxmlfromfilenames.xsl" label="inres2">
      <map:parameter name="dir" value="content/resource/"/>
      <map:parameter name="enclosing_element" value="resources"/>
   </map:transform>
   <map:serialize type="xml"/>
</map:match>

From my limited knowledge of Cocoon it appears that you should fetch the [tt]internal/resources.xml [/tt]URL and process that with the stylesheet you are developing. That XML document will have the structure:
Code:
<resources>
  <resource filename="resource_verizon">
    <name>Verizon Super Pages</name>
    <description>Browser accessibility to the White and Yellow Pages for the areas of the Maryland suburbs, greater Norther Virginia, and Washington D.C.</description>
    <url low="" high=""/>
    <provider>Verizon Directories Corporation</provider>
    <coverage_dates>2001-2003</coverage_dates>
    <status value="" expiredate=""/>
  </resource>
...
</resources>

So we would then have an input document that contains all the resources, thus obviating the need for my first variable. Herewith a modification:
Code:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
<!-- load a variable, $allSorted, with all resource nodes         sorted by <name> and capture for easy reference the initial letter of the name -->
    <xsl:variable name="allSorted">
        <xsl:for-each select="/resources/resource">
            <xsl:sort select="name"/>
            <sorted-entry><letter><xsl:value-of select="translate(substring(name,1,1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></letter><xsl:copy-of select="."/></sorted-entry>
        </xsl:for-each>
    </xsl:variable>
<html>
<body>
<!-- iterate over the sorted resource nodes -->
<xsl:for-each select="$allSorted/sorted-entry">
<xsl:sort select="letter"/>
<xsl:sort select="resource/name"/>
    <xsl:variable name="lastLetter" select="letter"/>
    <!-- if the index letter is not the same as the previous index letter
         a.  output the link array, and
         b.  output the anchor <a> tag for the beginning of the new letter
         (note: The first letter will not = the null previous letter
                which takes care of the links before the first letter -->
    <xsl:if test="not(preceding-sibling::sorted-entry[letter=$lastLetter])">
        <!-- output the link array  using the same logic presented for the outer loop
             only this time it is used to produce a single link for each letter actually used -->
        <xsl:for-each select="$allSorted/sorted-entry">
        <xsl:sort select="letter"/>
            <xsl:variable name="lastLink" select="letter"/>
            <xsl:if test="not(preceding-sibling::sorted-entry[letter=$lastLink])">
            <!-- since we are 'computing' the link href value, we use xsl:attribute -->
            <a><xsl:attribute name="href">#<xsl:value-of select="letter"/></xsl:attribute>
               <xsl:value-of select="letter"/>
            </a><xsl:text> </xsl:text>
            </xsl:if>
        </xsl:for-each>
        <!-- produce the anchor tag before the first entry for the new letter -->
        <a><xsl:attribute name="name"><xsl:value-of select="$lastLetter"/></xsl:attribute></a>
    </xsl:if>
<!-- output a resource -->
<h2><xsl:value-of select="resource/name"/></h2><br/><h3><xsl:value-of select="resource/description"/></h3>
</xsl:for-each>
<!-- output the final link array, after the last entry -->
<xsl:for-each select="$allSorted/sorted-entry">
<xsl:sort select="letter"/>
    <xsl:variable name="lastLink" select="letter"/>
    <xsl:if test="not(preceding-sibling::sorted-entry[letter=$lastLink])">
    <a><xsl:attribute name="href">#<xsl:value-of select="letter"/></xsl:attribute><xsl:value-of select="letter"/></a><xsl:text> </xsl:text>
    </xsl:if>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Tom Morrison
 
Okay, I have gone back to your original stylesheet and modified it. It may not look very much like your original, but I really did do that. :-D
Code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet  xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
<xsl:output method="html"/>

<xsl:key name="initialChar" match="resource" use="translate(substring(name,1,1),
           										  'abcdefghijklmnopqrstuvwxyz',
												  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<!-- define a variable to be used for link output (minor efficiency)-->
<xsl:variable name="lettersUsed">
    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
													translate(substring(name,1,1),
															  'abcdefghijklmnopqrstuvwxyz',
														      'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
	<letter><xsl:value-of select="translate(substring(name,1,1),
										    'abcdefghijklmnopqrstuvwxyz',
										    'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></letter>
	</xsl:for-each>
</xsl:variable>
		

<xsl:template match="/">
	<html>
	<body>
	<!-- iterate over all the unique initial letter values -->
    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
	  													        translate(substring(name,1,1),
														        'abcdefghijklmnopqrstuvwxyz',
														        'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
		<!-- sort the nodes for this initial letter value by name -->
		<xsl:sort select="name"/>
	  	<xsl:variable name="myChar" select="translate(substring(name,1,1),
													  'abcdefghijklmnopqrstuvwxyz',
												   	  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
		<!-- output the links -->
		<xsl:call-template name="genLinks"/> 
		<xsl:element name="a"><xsl:attribute name="name"><xsl:value-of select="string($myChar)"/></xsl:attribute></xsl:element>
		<!-- output all the nodes having this intial letter value -->
        <xsl:for-each select="key('initialChar',$myChar)">
			<xsl:sort select="name"/>
			<h2><xsl:value-of select="name"/></h2>
			<h3><xsl:value-of select="description"/></h3>
		</xsl:for-each>
	  </xsl:for-each>
		<!-- output the final links -->
		<xsl:call-template name="genLinks"/> 
	</body>
	</html>

</xsl:template>

<xsl:template name="genLinks">
	<center>
	<span style="letter-spacing:7px; font-size=12pt">
    <!-- The for-each will iterate exactly once for each unique initial letter. -->
        <xsl:for-each select="$lettersUsed/letter">
			<xsl:sort select="."/>
			<xsl:variable name="myChar" select="."/>
			<a><xsl:attribute name="href"><xsl:text>#</xsl:text><xsl:value-of select="$myChar"/></xsl:attribute>
			   <xsl:value-of select="$myChar"/></a>
			   <xsl:if test="position()!=last()"><xsl:text>-</xsl:text></xsl:if>
		</xsl:for-each>
    </span>
	</center>

</xsl:template>
</xsl:stylesheet>

(I did (re)learn a lesson on this. One cannot switch contexts in the middle of the Muench method. The explanation of this is too long for right now.)

Tom Morrison
 
Hello!
Thank you for your response!! I'm working on your most recent solution, but the <xsl:call-template name="genLinks"> is giving me problems. Is there anyway I can test to see what the value of $lettersUsed/letter is at a given point? I tried adding Letter= <xsl:value-of select="$lettersUsed/letter"> but all that printed was 'Letter=', a number of times.
TIA!
 
[tt]<xsl:value-of select="$lettersUsed/letter"> [/tt]probably does not do what you expect (I am unsure of the context you are using this) because [tt]select="$lettersUsed/letter" [/tt] actually selects a nodeset, one node per letter. I presume that you are attempting to display single letters, one at a time. In that case you would need to do something like
Code:
<xsl:for-each select="$lettersUsed/letter">
  Letter= <xsl:value-of select=".">
</xsl:for-each>

Tom Morrison
 
That's exactly what I'm looking to do...but what am I doing wrong. I have the <xsl:call-template nae="genLinks"/> lines in the template-match section, and this for the genLinks:

<xsl:template name="genLinks">
<center>
<span style="letter-spacing:7px; font-size=12pt">
<xsl:for-each select="$lettersUsed/letter">
<xsl:value-of select="."/>
</xsl:for-each>
</span>
</center>
</xsl:template>

I get a "java.lang.ClassCastException: org.apache.xpath.objects.XRTreeFrag" error
 
Looks fine to me. Works fine in Stylus Studio with both the builtin and MSXML v6 XSLT processors. However...

I tried the same files on libxml/libxslt (fairly old version) and it failed when trying to evaluate that xsl:for-each select attribute. With verbose output, I can see that it is finding the variable, but something in the evaluation goes bad.

I am not sure what XSLT processor is being used in Cocoon.

Not to worry. I was using the template as a subroutine to save a few lines of code. Just yank thise lines of code from the template up into the other template replacing the two places the xsl:call-template is used.

Tom Morrison
 
If I followed what you said, I removed the xsl:call-template lines and replaced them with:

<center>
<span style="letter-spacing:7px; font-size=12pt">
<xsl:for-each select="$lettersUsed/letter">
<xsl:value-of select="."/>
</xsl:for-each>
</span>
</center>

but that still doesn't work so maybe I didn't follow you correctly. [morning]
 
Again, I tried that too with libxslt and that didn't work, despite the fact that Stylus Studio builtin and MSXML v6 are both happy. Try this (wordier, but executed on libxslt).
Code:
<xsl:stylesheet  xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
<xsl:output method="html"/>

<xsl:key name="initialChar" match="resource" use="translate(substring(name,1,1),
           										  'abcdefghijklmnopqrstuvwxyz',
												  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />

<xsl:template match="/">
	<html>
	<body>
	<!-- iterate over all the unique initial letter values -->
    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
	  													        translate(substring(name,1,1),
														        'abcdefghijklmnopqrstuvwxyz',
														        'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
		<!-- sort the nodes for this initial letter value by name -->
		<xsl:sort select="name"/>
	  	<xsl:variable name="myChar" select="translate(substring(name,1,1),
													  'abcdefghijklmnopqrstuvwxyz',
												   	  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
		<!-- output the links -->
		<center>
		<span style="letter-spacing:7px; font-size=12pt">
	    <!-- The for-each will iterate exactly once for each unique initial letter. -->
	    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
				   													translate(substring(name,1,1),
																	'abcdefghijklmnopqrstuvwxyz',
														    		'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
			<xsl:sort select="name"/>
			<xsl:variable name="myLinkChar" select="translate(substring(name,1,1),
										    'abcdefghijklmnopqrstuvwxyz',
										    'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
			<a><xsl:attribute name="href"><xsl:text>#</xsl:text><xsl:value-of select="$myLinkChar"/></xsl:attribute>
			   <xsl:value-of select="$myLinkChar"/></a>
			   <xsl:if test="position()!=last()"><xsl:text>-</xsl:text></xsl:if>
		</xsl:for-each>
	    </span>
		</center>
		<xsl:element name="a"><xsl:attribute name="name"><xsl:value-of select="string($myChar)"/></xsl:attribute></xsl:element>
		<!-- output all the nodes having this intial letter value -->
        <xsl:for-each select="key('initialChar',$myChar)">
			<xsl:sort select="name"/>
			<h2><xsl:value-of select="name"/></h2>
			<h3><xsl:value-of select="description"/></h3>
		</xsl:for-each>
	  </xsl:for-each>
		<!-- output the final links -->
	<center>
	<span style="letter-spacing:7px; font-size=12pt">
    <!-- The for-each will iterate exactly once for each unique initial letter. -->
    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
			   													translate(substring(name,1,1),
																'abcdefghijklmnopqrstuvwxyz',
													    		'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
		<xsl:sort select="name"/>
		<xsl:variable name="myLinkChar" select="translate(substring(name,1,1),
									    'abcdefghijklmnopqrstuvwxyz',
									    'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
		<a><xsl:attribute name="href"><xsl:text>#</xsl:text><xsl:value-of select="$myLinkChar"/></xsl:attribute>
		   <xsl:value-of select="$myLinkChar"/></a>
		   <xsl:if test="position()!=last()"><xsl:text>-</xsl:text></xsl:if>
	</xsl:for-each>
    </span>
	</center>
	</body>
	</html>

</xsl:template>

</xsl:stylesheet>

Tom Morrison
 
And back to using <xsl:call-template>
Code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet  xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
<xsl:output method="html"/>

<xsl:key name="initialChar" match="resource" use="translate(substring(name,1,1),
           										  'abcdefghijklmnopqrstuvwxyz',
												  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />

<xsl:template match="/">
	<html>
	<body>
	<!-- iterate over all the unique initial letter values -->
    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
	  													        translate(substring(name,1,1),
														        'abcdefghijklmnopqrstuvwxyz',
														        'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
		<!-- sort the nodes for this initial letter value by name -->
		<xsl:sort select="name"/>
	  	<xsl:variable name="myChar" select="translate(substring(name,1,1),
													  'abcdefghijklmnopqrstuvwxyz',
												   	  'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
		<!-- output the links -->
		<xsl:call-template name="genLinks"/>
		<xsl:element name="a"><xsl:attribute name="name"><xsl:value-of select="string($myChar)"/></xsl:attribute></xsl:element>
		<!-- output all the nodes having this intial letter value -->
        <xsl:for-each select="key('initialChar',$myChar)">
			<xsl:sort select="name"/>
			<h2><xsl:value-of select="name"/></h2>
			<h3><xsl:value-of select="description"/></h3>
		</xsl:for-each>
	  </xsl:for-each>
		<!-- output the final links -->
		<xsl:call-template name="genLinks"/>
	</body>
	</html>

</xsl:template>

<xsl:template name="genLinks">
		<span style="letter-spacing:7px; font-size=12pt">
		<center>
	    <!-- The for-each will iterate exactly once for each unique initial letter. -->
	    <xsl:for-each select="//resource[generate-id(.)=generate-id(key('initialChar', 
				   													translate(substring(name,1,1),
																	'abcdefghijklmnopqrstuvwxyz',
														    		'ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1])]">
			<xsl:sort select="name"/>
			<xsl:variable name="myLinkChar" select="translate(substring(name,1,1),
										    'abcdefghijklmnopqrstuvwxyz',
										    'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
			<a><xsl:attribute name="href"><xsl:text>#</xsl:text><xsl:value-of select="$myLinkChar"/></xsl:attribute>
			   <xsl:value-of select="$myLinkChar"/></a>
			   <xsl:if test="position()!=last()"><xsl:text>-</xsl:text></xsl:if>
		</xsl:for-each>
		</center>
	    </span>
</xsl:template>

</xsl:stylesheet>

Tom Morrison
 
IT WORKED!!!!!!!! [lipstick] You're my hero!!! [medal]
Thank you thank you thank you thank you THANK YOU!
You deserve a trillion stars...but I don't think I'm allowed to do that.

Now I think I'm going to search the classifieds for a new job. [wink]

On a more serious note, thank you so very much for all of your time and hard work and your patience and your persistence...I was about to throw my own hands up! I've got a lot to learn!!!
Thank you again!!!

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top