Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old September 11th, 2014, 08:55 AM
Registered User
 
Join Date: Sep 2014
Posts: 3
Thanks: 1
Thanked 0 Times in 0 Posts
Default Issue with using xsl:key with xalan:nodeset

G'day,

Running on Windows server 2k8, Xalan v2.7.1.

I wrote a quick xalan java extension to read and return a nodeset of filenames in a directory. Each file in this directory is an xml file containing department information.

I then loop through this nodeset, using the document() function, copy out the main department node from each xml document to a result tree (xsl variable).

I need to turn this result tree fragment into a node-set, so i use xalan:nodeset extension.

I need to generate an alphabetical listing of department links, with an alphabetical link bar at the top of the page, linking down to each letter grouping for departments.

Not sure if this is clear or not.

My main problem is that I'm getting an error on the xsl:key line... invalid tokens.

Here's my code:

Code:
<xsl:variable name="deptIndexNode">
   <xsl:for-each
     select="dir-ext:fileListAsXml('c:/temp/data')/fileList/name">
	 <xsl:variable name="dcrXml" select="document(concat('../data/',.))" /> 
					<xsl:copy-of select="$dcrXml/department"/>
	 </xsl:for-each> 
	 </xsl:variable>

<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

<xsl:variable name="accentedChars" select="'ÀÂÄÉËÊÈÏÎÒÔÖÜÛÙÇ'" />
<xsl:variable name="baseChars" select="'AAAEEEEIIOOOUUUC'" />

<xsl:key name="firstLetter" match="xalan:nodeset($deptIndexNode)/department" use="translate(translate(substring(normalize-space(name_en),1,1),$smallcase,$uppercase),$accentedChars,$baseChars)" />
the error is thrown on my xsl:key line:
2014-09-11 08:50:48,651 ERROR [STDERR] SystemId Unknown; Line #27; Column #196; Extra illegal tokens: '(', '$', 'deptIndexNode', ')', '/', 'department'

Am i out to lunch here? is there a better way to do this? I can confirm that my xalan extension does work, and am able to process each xml file without any issue... only when i try to build up the key map on the generated result tree is where i'm stumped.

I'm basing this on Jeni Tennison's article on Muechian grouping method...

thanks for any tips/advice..

Edit: From Jeni's article:
"Finally, it can be quite complicated to use keys where the nodes that you want to group are spread across different source documents. "

this is pretty much what I'm dealing with here... trying to group department nodes, with each department node in its own xml file.

Last edited by stego; September 11th, 2014 at 09:22 AM.. Reason: Added quote from Jeni's article
 
Old September 11th, 2014, 09:23 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

The match attribute for xsl:key needs to be a valid XSLT pattern. That doesn't permit a call on xalan:nodeset() (or any other function, with a couple of exceptions like id() and key()).

I'm afraid I have no idea whether Xalan allows building of keys against a temporary tree created using xalan:node-set(). We're outside the scope of the spec here.

Is there a better solution? Yes - use XSLT 2.0. (Which in practice means Saxon).
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
The Following User Says Thank You to mhkay For This Useful Post:
stego (September 11th, 2014)
 
Old September 11th, 2014, 09:28 AM
Registered User
 
Join Date: Sep 2014
Posts: 3
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Thanks... reading the W3C spec on key function... I read:

Quote:
It is an error for the value of either the use attribute or the match attribute to contain a VariableReference.
So I'm SOL on this one...can't use Saxon i'm afraid, since i'm using a COTS CMS provided xml parser...
 
Old September 11th, 2014, 11:37 AM
Registered User
 
Join Date: Sep 2014
Posts: 3
Thanks: 1
Thanked 0 Times in 0 Posts
Default

I seem to have managed to solve my problem! ;-)

Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:dir-ext="xalan://mypkg.news.xalan.ext.Directory" 
	xmlns:xalan="http://xml.apache.org/xalan"
	xmlns:redirect="http://xml.apache.org/xalan/redirect"
    version="1.0"
	extension-element-prefixes="dir-ext xalan"
	exclude-result-prefixes="xalan dir-ext">

<xsl:output method="html"/>

    
   <xsl:variable name="deptIndexNode">
   <departments>
   <xsl:for-each
     select="dir-ext:fileListAsXml('c:/temp/data')/fileList/name">
	 <xsl:variable name="dcrXml" select="document(concat('../data/',.))" /> 
					<xsl:copy-of select="$dcrXml/department"/>
	 </xsl:for-each> 
	 </departments>
	 </xsl:variable>
	 
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

<xsl:variable name="accentedChars" select="'ÀÂÄÉËÊÈÏÎÒÔÖÜÛÙÇ'" />
<xsl:variable name="baseChars" select="'AAAEEEEIIOOOUUUC'" />


<xsl:key name="firstLetter" match="department" use="translate(translate(substring(normalize-space(name_fr),1,1),$smallcase,$uppercase),$accentedChars,$baseChars)" />

	<xsl:template match="/">

 				<xsl:apply-templates select="xalan:nodeset($deptIndexNode)" mode="alphaNavbar" />
				<xsl:apply-templates select="xalan:nodeset($deptIndexNode)" mode="deptList" />

	 </xsl:template>
	 
	 
	 <xsl:template match="departments" mode="alphaNavbar">
<div class="row margin-bottom-none">
            <div class="col-md-12">
                <ul class="pagination">
					<xsl:call-template name="alphabetLinks"/>
                </ul>
            </div>
        </div> 	
	 
	 </xsl:template>
	 
	 <xsl:template match="departments" mode="deptList">
	 
	 <!--  Grouping Using the Muenchian Method 
http://jenitennison.com/xslt/grouping/muenchian.html
 -->         
                
     <xsl:for-each select="department[count(. | key('firstLetter', translate(translate(substring(normalize-space(name_fr),1,1),$smallcase,$uppercase),$accentedChars,$baseChars))[1]) = 1]">  
	 <xsl:variable name="letterAnchorLabel" select="translate(translate(substring(normalize-space(name_fr),1,1),$smallcase,$uppercase),$accentedChars,$baseChars)" />
		<h2><a id="{$letterAnchorLabel}"></a><xsl:value-of select="$letterAnchorLabel" /><span class="wb-inv">: Departments and agencies starting with the letter <xsl:value-of select="$letterAnchorLabel" /></span></h2> 
     	<ul>
		<xsl:for-each select="key('firstLetter', translate(translate(substring(normalize-space(name_fr),1,1),$smallcase,$uppercase),$accentedChars,$baseChars))">
				<xsl:sort select="name_fr" lang="fr"/>
				<li>
                 <a href="/inet-inet/gocnr-sdpgdc/10/dptlndg-en.do?mthd=dplnd&amp;crtr.dpt1D={@id}"><xsl:value-of select="name_fr"/></a>
				 <a href="/inet-inet/gocnr-sdpgdc/10/feed-en.do?mthd=xml&amp;crtr.dpt1D={@id}" class="cn-rssfeed-icon pull-left"><span class="wb-inv">RSS feed for </span><span class="wb-inv"><xsl:value-of select="name_fr"/></span></a>
                                <span class="clearfix"></span>
                  </li>
     	</xsl:for-each>
		</ul>
     </xsl:for-each>   
 
	 </xsl:template>

	 <xsl:template name="alphabetLinks">
  <xsl:param name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
  <xsl:variable name="letter" select="substring($alphabet, 1, 1)" />
    <xsl:choose>
    <xsl:when test="key('firstLetter', $letter)">
             <li><a href="#{$letter}"><xsl:value-of select="$letter"/><span class="wb-inv">: Departments and agencies starting with the letter <xsl:value-of select="$letter"/></span></a></li>
    </xsl:when>
    <xsl:otherwise>
	<li class="disabled"><xsl:value-of select="$letter"/><span class="wb-inv">: Departments and agencies starting with the letter <xsl:value-of select="$letter"/></span></li>
    </xsl:otherwise>
  </xsl:choose>
  <xsl:variable name="rest" select="substring($alphabet, 2)" />
  <xsl:if test="$rest">
    <xsl:call-template name="alphabetLinks">
      <xsl:with-param name="alphabet" select="$rest" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>
this generates my expected html output... seems this solution is "tricking" the key into a different context... not sure, but it works.





Similar Threads
Thread Thread Starter Forum Replies Last Post
proper use of xsl:key? ilyaz XSLT 5 December 10th, 2010 12:39 PM
xsl:key get value of ancestor bonekrusher XSLT 5 April 24th, 2009 11:17 AM
Javascript in Xsl using-Xalan-Problem angeshwar XSLT 1 May 7th, 2008 12:36 AM
Using key() and <xsl:key> freddy XSLT 2 January 18th, 2007 08:55 PM
how to return nodeset in template in xsl:variable alexshiell XSLT 3 March 18th, 2005 01:36 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.