[xsl] RTF variables, node-set and namespaces

Subject: [xsl] RTF variables, node-set and namespaces
From: "cking" <cking@xxxxxxxxxx>
Date: Mon, 6 Sep 2004 13:05:00 +0200
Hi y'all

There's something about node-sets I fail to understand.
Say, I have a variable holding a result tree fragment:

  <xsl:variable name="rtf-words">
    <word>one</word>
    <word>two</word>
    <word>three</word>
  </xsl:variable>

Suppose I want to access the second <word> element:
select="exsl:node-set($rtf-words)/word[2]". That works fine
as long as the stylesheet output is 'simple' xml. But when I
try this in an xhtml-output stylesheet, it doesn't work anymore.

Test stylesheet: (used against any xml doc)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
 xmlns="http://www.w3.org/1999/xhtml";
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:exsl="http://exslt.org/common";
 extension-element-prefixes="exsl"
 >
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
  />
  <xsl:variable name="rtf-words">
    <word>one</word>
    <word>two</word>
    <word>three</word>
  </xsl:variable>
  <xsl:variable name="rtf-ul">
    <ul xmlns="http://www.w3.org/1999/xhtml";>
     <li>one</li>
     <li>two</li>
     <li>three</li>
    </ul>
  </xsl:variable>
  <xsl:template match="/">
  <html xmlns="http://www.w3.org/1999/xhtml";>
   <head><title>test node-set</title></head>
   <body>
    <xsl:apply-templates/>
   </body>
  </html>
  </xsl:template>
  <xsl:template match="/*">
   <ul><xsl:apply-templates select="exsl:node-set($rtf-words)/word" mode="li"/></ul>
   <ul><xsl:apply-templates select="exsl:node-set($rtf-ul)/ul/li" mode="li"/></ul>
  </xsl:template>
  <xsl:template match="*" mode="li">
    <li><xsl:value-of select="."/></li>
  </xsl:template>
</xsl:stylesheet>

Output: (saxon 6.5.3)
<ul/>
<ul/>

Expected output:
<ul><li>one</li><li>two</li><li>three</li></ul>
<ul><li>one</li><li>two</li><li>three</li></ul>

The easiest way to solve this, is using "*" instead of the element names, like
    select="exsl:node-set($rtf-words)/*"
    select="exsl:node-set($rtf-ul)/*/*"

That works, and in most cases it's OK to use "*" because the element names
don't really matter, but I can't understand why:

select="exsl:node-set($rtf-words)/word" and
select="exsl:node-set($rtf-words)/*[self::word]" don't work, but
select="exsl:node-set($rtf-words)/*[name()='word']" does.

It must have something to do with namespaces, 
because I found out that adding xmlns="" also helps:

  <xsl:variable name="rtf-words">
    <word xmlns="">one</word>
    <word xmlns="">two</word>
    <word xmlns="">three</word>
  </xsl:variable>
  <xsl:variable name="rtf-ul">
    <ul xmlns="">
     <li>one</li>
     <li>two</li>
     <li>three</li>
    </ul>
  </xsl:variable>

That does give the expected output. But it puzzles me because I would think
esp. the <ul> element *should* be in xmlns="http://www.w3.org/1999/xhtml";

It also puzzles me that apparently, [self::word] is not the same as [name()='word']

Any thoughts?

Anton Triest

Current Thread