[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] Using key() from outside the default namespace


Subject: [xsl] Using key() from outside the default namespace
From: Peter Flynn <peter@xxxxxxxxxxx>
Date: 04 Aug 2003 18:46:49 +0100

I'm experimenting with portable ways of specifying bibliographic
reference formatting in XML so that it can be applied to documents in
any DTD or Schema. The objective is to avoid having to hard-code
complex XSL[T] for every output variant, when it's far faster and
easier to specify and maintain the layout using a generic document
type designed for the purpose. I'm having trouble using key() to get
information from the main document namespace while processing within
the namespace of an auxiliary document.

   How do I get a key() which indexes nodes in the main
   namespace to work if I need to invoke it from within
   a for-each which places the context in a different
   namespace, without triggering a new instance of the
   output document?

(See caveat at end: this is *different* from the examples in the FAQ
and elsewhere that I have found. Unless I've missed something.)

I have file of bibliographic references mydoc.xml (which could be
DocBook's <bibliography>, TEI's <listBibl>, etc). Each entry has an ID
attribute and a reference type attribute (eg Book, Article, Report,
etc), and the publisher is identified in an attribute on the
containing list. All standard stuff, no surprises.

I have an auxiliary XML file formats.xml containing specifications of
the formatting for these reference types, grouped in containers by
publisher (eg Elsevier Article, Kluwer Book, IEEE Report, etc),
stripped of all the typographic stuff here for simplicity:

   <publisher name="kluwer">
     <document type="article">
       <author>
         <surname/>
         <initials/>
       </author>
       <date/>
       <title/>
       <journal/>
       <volume/>
       <issue/>
       <pages/>
     </document>
     ...
   </publisher>
   ...

When doing the references in the main file, the template which handles
each entry must process the correct formatting subelements for the
specified publisher and document type in their document order. This is
done with a for-each on
document('formats.xml')//publisher[@name=$publisher]/document[@type=$entrytype]/*
So far, so good: this ensures the output occurs in the correct
sequence.

I have keys set up which identify the relevant element from the main
file for each of the formatting subelements processed, eg

   <xsl:key name="kluwer-article-author-surname" 
            match="//biblioentry/author/surname"
            use="ancestor::biblioentry/@id"/>

But it is necessary to use these keys while inside the for-each which
handles the formatting subelements (it also calls a named template
which handles the output formatting), so the context node is inside
the namespace of the formats.xml file, not the main file. They keys
have been tested with a value-of while in the default (main file)
namespace, and they correctly return the desired values.

I did make one attempt by using a namespace on the main file, so the
key names (and thus the first argument to the key function) were of
the form docbook:kluwer-article-author-surname, but this didn't return
any values.

The recommendation in most books and the FAQ is to use a dummy
for-each on a global variable to change the namespace back to the main
document, eg

   <xsl:variable name="maindoc" select="/"/>

   <xsl:for-each select="biblioentry">

     ...set up variables to hold this entry ID and
        construct the publisher-documenttype-elements key names...

     <xsl:for-each select="document(as above...)">
       <xsl:call-template name="formatter">
         ...various parameters...
         <xsl:with-param name="data-source">
           <xsl:for-each select="$maindoc">
             <xsl:value-of select="key($pub-doc-path,$entryID)"/>
           </xsl:for-each>
         </xsl:with-param>
       </xsl:call-template>
     </xsl:for-each>
     ...

The value-of for the key() works *outside* the for-each on document()
(of course, being in the default namespace), but this method outputs
a new 
<html><head><title>...</title><link to
css></head><body>foo</body></html>
for *every* formatting subelement processed. Probably unsurprisingly,
as it's returning to the main namespace with a node-set, so it looks
for a matching template and fires it. It does of course also output
the data retrieved from the key...but how do I prevent it firing an
unwanted template at the same time.

I've experimented with making $maindoc point at other (innocuous)
locations in the main document, but that still triggers what Saxon
sees as a new instance of the output document.

** $64,000 question (actually I'll buy a pint in Philly) **
*                                                         *
*  How do I get a key() which indexes nodes in the main   *
*  namespace to work if I need to invoke it from within   *
*  a for-each which places the context in a different     *
*  namespace, without triggering a new instance of the    *
*  output document?                                       *
*                                                         *
***********************************************************

Note this is *different* from the examples I have seen, which merely
want to reference a key() in another namespace *from within the
default namespace*. That one's easy. This one doesn't seem to be.

///Peter




 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords
xml