[xsl] xml:base, resolve-uri and imported xslt files: how to get the importing base url from imported xslt

Subject: [xsl] xml:base, resolve-uri and imported xslt files: how to get the importing base url from imported xslt
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Mon, 09 Oct 2006 16:33:20 +0200
Dear List,

For what I understand from the specs and Michael Kay's books, the following may very well be impossible: find the base URL of the importing stylesheet from an imported stylesheet.

The use case:
I have a set of generalized xslt files. These are, naturally, imported in more specific xslt files. One of these generalized xslt files (let's call it common.xslt) must take an external document that has some configuration options and parse these options. I declare it like this in the root:

<xsl:variable name="configuration" select="document($param-config-url) />

My specific xslt file (let's call it specific.xslt), I use this variable $configuration exhaustively. But the configuration xml file, referred to by global parameter $param-config-url, is relative to the root of specific.xslt. Is there a way to tell my imported xslt file where to look?

I tried the following to no avail:
<xsl:import href="../common/common.xslt" xml:base="." />
<xsl:import href="../common/common.xslt" xml:base="file://specificpath/specific.xslt" />
<xsl:value-of select="$configuration" xml:base="file://specificpath/specific.xslt" />

Even if these could work, I still cannot make xml:base dynamic, so only the first option could be useful. I also tried xml:base on either root xslt element and I tried if xsl:include had a different way or resolving the uri.

The specs say (my interpretation):
- the uri is relative to the base uri of the xslt document or the base uri of the source document, depending the location of the first argument of document()
- the uri is relative to the current xslt instruction's base-uri
- if an xslt instruction does not have a base uri, it uses the base uri of the parent, up until the uri of the xslt document.

Unfortunately, my parameters and variables are in global scope, meaning that there's not context node I can trick to use as base href from. Furthermore, I cannot use a variable, because a variable in the importing xslt is not known in the imported xslt.

Only option I see, so far, is setting another global parameter that must define the base uri for the imported xslt. I hoped that one relative uri would suffice, but I guess I have to resort to using a specific absolute location for each importing xslt.

Any better ideas? Did I miss something from the specs? In a way I hoped that the import precedence would apply here, but apparently, that is not involved.

Below is a minimum set of data and XSLT that can be used to mimic what I tried to achieve. I used saxon for parsing.

Abel Braaksma

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
<xsl:variable name="common-uri" select="resolve-uri('')" />
<!-- todo: how to get this ??? -->
<xsl:variable name="rel-from-spec" select="resolve-uri('')" /> </xsl:stylesheet>

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
<xsl:import href="../common/common.xslt" />

<xsl:template match="/" >
importing (specific) uri: <xsl:value-of select="resolve-uri('')" />
imported (common) uri: <xsl:value-of select="$common-uri" />
source document uri: <xsl:value-of select="resolve-uri(base-uri(.))" />
external document uri: <xsl:value-of select="resolve-uri($common-uri)" />
get specific from common: <xsl:value-of select="$rel-from-spec" xml:base="." />

=== TEST XML === <root> HELLO WORLD! </root>

Current Thread