Solved

XSL cycle through alphabet

Posted on 2004-04-14
8
1,065 Views
Last Modified: 2008-03-10
I want to display the alphabet, and where there is a matching entry in my XML, I want the letter to be a link (ie for letters ACDFSW).  So for instance I have my XML doc:

<root><data><alphabet><char>A</char></alphabet><alphabet><char>C</char></alphabet><alphabet><char>D</char></alphabet><alphabet><char>F</char></alphabet><alphabet><char>S</char></alphabet><alphabet><char>W</char></alphabet></data></root>

How can I get my XSL to display each other letter?

Hope this is clear!
Ta,
eq
0
Comment
Question by:equentin
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
8 Comments
 
LVL 5

Expert Comment

by:conorj
ID: 10824251
Hi Eq,

try the following. It uses a global variable to store all the letters of the
alphabet and a key to reference the char elements in your XML document.
..............
<xsl:variable name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:key match="char" name="chars" use="." />

<xsl:template match="/">
    <xsl:call-template name="process.alphabet">
        <xsl:with-param name="letters" select="$alphabet" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="process.alphabet">
    <xsl:param name="letters" select="''" />
    <xsl:variable name="thisletter" select="substring($letters, 1, 1)" />
    <xsl:if test="$letters != ''">
        <xsl:choose>
            <xsl:when test="key('chars', $thisletter)">
                <a href="{$thisletter}.html"><xsl:value-of select="$thisletter" /></a>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$thisletter" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:call-template name="process.alphabet">
            <xsl:with-param name="letters" select="substring($letters, 2)" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>
..............

HTH.

rgds,
Conor.
0
 

Author Comment

by:equentin
ID: 10824378
Hmmm...  Thanks for that - but being a bit of a novice at XSL, how do I get my char xml into your line:
<xsl:key match="char" name="chars" use="." />

The way I've been referring to my node sets before is to use
<xsl:for-each select="msxsl:node-set($pageData)//char/." > if that helps at all.

Sorry for any vagueness - it's all v confusing to me!

Ta,
eq
0
 
LVL 5

Expert Comment

by:conorj
ID: 10831145
Eq,

what does $pageData refer to?? Could you show the relevant parts of your XSLT??

rgds,
Conor.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:equentin
ID: 10831185
I'm inheriting this project off someone else, so it may not have been written in the best way, and we're all a bit of novices in the XML/XSL arena, so apologies if it's a bit messy!

Ok, the XSL stylesheet is called from an ASP page that gets the XML out of SQL server and creates the XML.  It's in the format of <root><data><alphabet><char>A</char></alphabet>[etc]</root>
ASP then applies the XML to a variable (pagedata) using loadData.documentElement.  In the stylesheet we get the data out of this by using a command like <xsl:for-each select="msxsl:node-set($pageData)//alphabet/." >.

Hope this makes things clearer - appreciate it's a tad vague, so I've increased the points to 500.

Cheers,
eq
0
 
LVL 5

Expert Comment

by:conorj
ID: 10831493
Eq,

Since you are using the msxsl:nodeset element I assume the XML is inside a variable/parameter.
I have placed the XML data inside a param named "pageData".

As a matter of interest what is your stylesheet applied to?? And how is the variable pageData passed to the stylesheet??

<xsl:stylesheet version="1.0" exclude-result-prefixes="msxsl"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt">

<xsl:param name="pageData">
<root><data><alphabet><char>A</char></alphabet><alphabet><char>C</char></alphabet><alphabet><char>D</char></alphabet>
<alphabet><char>F</char></alphabet><alphabet><char>S</char></alphabet><alphabet><char>W</char></alphabet></data></root>
</xsl:param>
<xsl:variable name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:key match="char" name="chars" use="." />

<xsl:template match="/">
    <xsl:call-template name="process.alphabet">
        <xsl:with-param name="letters" select="$alphabet" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="process.alphabet">
    <xsl:param name="letters" select="''" />
    <xsl:variable name="thisletter" select="substring($letters, 1, 1)" />
    <xsl:if test="$letters != ''">
        <xsl:for-each select="msxsl:node-set($pageData)">
            <xsl:choose>
                <xsl:when test="key('chars', $thisletter)">
                    <a href="{$thisletter}.html"><xsl:value-of select="$thisletter" /></a>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$thisletter" />
                </xsl:otherwise>
            </xsl:choose>
            <xsl:call-template name="process.alphabet">
                <xsl:with-param name="letters" select="substring($letters, 2)" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:if>
</xsl:template>
</xsl:stylesheet>

rgds,
Conor.
0
 

Author Comment

by:equentin
ID: 10831803
I see what you've done and it works fine, but I just cannot get it to work when I try it to apply it to my "pageData".  In fact, it just hangs...  I tried to change the
 <xsl:for-each select="msxsl:node-set($pageData)">
to
 <xsl:for-each select="msxsl:node-set($pageData)//alphabet/.">
but that causes it to die.

What does the <xsl:key match="char" name="chars" use="." /> do?

This is a simplified version of the code in the asp page that sets up the XSL:

xslPage = "pages/xsl/companies.xsl"
xmlPage = "template/xml/main.xml"

pageData = "<root><data><alphabet><char>A</char></alphabet><alphabet><char>C</char></alphabet><alphabet><char>D</char></alphabet>
<alphabet><char>F</char></alphabet><alphabet><char>S</char></alphabet><alphabet><char>W</char></alphabet></data></root>"


Set Append = Server.CreateObject("Msxml2.DOMDocument.3.0")

      Append.loadXML(xmlMenuID)
      xmlDoc.async = false
      xslDoc.async = false
      xmlDoc.load(server.mapPath(xmlPage))
      xslDoc.load(server.mapPath(xslPage))
      
      Set template = Server.CreateObject("MSXML2.XSLTemplate")
            Set template.stylesheet = xslDoc
                  Set proc = template.createProcessor
                        proc.input = xmlDoc
                        proc.output = Response
                  
                        proc.addParameter "type", typeID
                        proc.addParameter "querystring", strQueryString
                        proc.addParameter "font", Session("font")
                        proc.addParameter "color", Session("color")
                        proc.addParameter "pageID", pageID
                        proc.addParameter "companyID", companyID
                        proc.addParameter "menuID", Append.documentElement
                        
                        If pageData <> "" Then
                              proc.addParameter "pageData", loadData.documentElement
                        End If

                        proc.transform()
0
 
LVL 5

Accepted Solution

by:
conorj earned 500 total points
ID: 10840464
Eq,

not sure what loadData is but i created a simplified version of the ASP shown below. I made pageData a
DomDocument object as this removes the need for msxsl:nodeset in the XSLT.
<xsl:key match="char" name="chars" use="."> creates an index of all the <char> elements in the document.
key('chars', $thisletter) returns any char node whose text content is equal to $thisletter.
See http://www.dpawson.co.uk/xsl/sect2/N4852.html for the official FAQ on keys and their usage.

ASP:
<%
xslPage = "test.xsl"
xmlPage = "test.xml"

Set pageData = Server.CreateObject("Msxml2.freethreadedDOMDocument.3.0")
pageData.loadXML "<root><data><alphabet><char>A</char></alphabet><alphabet><char>C</char></alphabet><alphabet><char>D</char></alphabet><alphabet><char>F</char></alphabet><alphabet><char>S</char></alphabet><alphabet><char>W</char></alphabet></data></root>"

Set xmlDoc = Server.CreateObject("Msxml2.freethreadedDOMDocument.3.0")
Set xslDoc = Server.CreateObject("Msxml2.freethreadedDOMDocument.3.0")
     xmlDoc.async = false
     xslDoc.async = false
     xmlDoc.load(server.mapPath(xmlPage))
     xslDoc.load(server.mapPath(xslPage))
     Set template = Server.CreateObject("MSXML2.XSLTemplate")
     Set template.stylesheet = xslDoc
     Set proc = template.createProcessor
     proc.input = xmlDoc
     proc.output = Response
     If pageData.xml <> "" Then
         proc.addParameter "pageData", pageData
     End If
       'proc.transform
     response.write(proc.transform)
%>

XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="pageData" />
<xsl:variable name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:key match="char" name="chars" use="." />

<xsl:template match="/">
      <xsl:call-template name="process.alphabet">
            <xsl:with-param name="letters" select="$alphabet" />
      </xsl:call-template>
</xsl:template>

<xsl:template name="process.alphabet">
      <xsl:param name="letters" select="''" />
      <xsl:variable name="thisletter" select="substring($letters, 1, 1)" />
      <xsl:if test="$letters != ''">
            <xsl:choose>
                  <xsl:when test="key('chars', $thisletter)">
                        <a href="{$thisletter}.html"><xsl:value-of select="$thisletter" /></a>
                  </xsl:when>
                  <xsl:otherwise>
                        <xsl:value-of select="$thisletter" />
                  </xsl:otherwise>
            </xsl:choose>
            <xsl:call-template name="process.alphabet">
                  <xsl:with-param name="letters" select="substring($letters, 2)" />
            </xsl:call-template>
      </xsl:if>
</xsl:template>
</xsl:stylesheet>


HTH.

rgds,
Conor.
0
 

Author Comment

by:equentin
ID: 10840550
Thanks for the help Conor - I'm off on hols imminently for a couple of weeks, so I'm prob not going to get the chance to go through it.  Thanks for your advice - I'm not certain the site was created in the cleverest way as it is.  

So in the meantime I'll award you the points, as you answered my initial question perfectly.

Cheers,
eq
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Test ddwrt:UserLookup 1 77
Powershell XML in variable 4 40
splitting a sting into elements 6 66
Load XML element 3 42
The Problem How to write an Xquery that works like a SQL outer join, providing placeholders for absent data on the outer side?  I give a bit more background at the end. The situation expressed as relational data Let’s work through this.  I’ve …
The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…
How to Install VMware Tools in Red Hat Enterprise Linux 6.4 (RHEL 6.4) Step-by-Step Tutorial

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question