xsl-url -- passing xsl:variable's to imported stylesheets in XSLT 1.0

6/9/2009

Introduction

The xsl-url pages here correspond to article
msg00070.html on xsl-list and are provided as Webpage because of the interactive nature of its samples as well as the better layout than in a simple email.

Opening an XML file in a browser containing a xml-stylesheet programming instruction executes the referenced stylesheet with the XML file's data as input. Since the binding for the stylesheet to be executed (referenced by @href) is fixed in the XML file, it would be useful to have access to the browser URL inclusive its query string inside the stylesheet for influencing the transformation of the data.

It is not possible to access the browser URL for XSLT 1.0 and XSLT 2.0.
Though it has been identified as useful at the end of the follwoing mozilla page:
https://developer.mozilla.org/En/XSLT/PI_Parameters
(unfortunately there seems to be no activity since March last year)

Although it is generally not possible to access the browser URL from within an executed stylesheet there is a solution for browsers supporting msxsl:script, but this is NOT a cross browser solution and relies on JScript, see msgeturl.

xsl-url method

While it is not possible to access the browser URL from within a stylesheet in general, the follwoing provides a solution allowing to have several XML documents referencing a single XML data document and enhancing this reference by providing additional information, a URL with query string in examples cdcatalog.1.xml and cdcatalog.2.xml (see listings section below). This concept is comparable to HTML anchor targets.
Basically the following needs to be done:

It is possible to pass parameters to templates called by xsl:apply-templates and via xsl:with-param.
But this does not work for xsl:apply-imports for XSLT 1.0 (fixed in XSLT 2.0):
http://www.w3.org/TR/xslt#section-Passing-Parameters-to-Templates
http://www.biglist.com/lists/xsl-list/archives/200303/msg00205.html

How cdcatalog.xsl.xsl works:

  1. open the XML file referenced by xsl-url with the document() function
  2. iterate through the root node of this document by xsl:for-each to set the root node as current node
  3. inside the xsl:for-each the current template rule becomes null
  4. do a matching xsl:apply-templates to get a non-null current template rule again (this a a requirement for executing xsl:apply-imports)
  5. decision whether to work on the referencing document or doing an xsl:apply-imports is done based on the presence of /xsl-url

Pros of the xsl-url solution:

Listings

cdcatalog.1.xml (click to see result of transformation) cdcatalog.2.xml (click to see result of transformation)
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl.xsl"?>
<xsl-url>cdcatalog.xml?query</xsl-url>
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl.xsl"?>
<xsl-url>cdcatalog.xml?answer=42</xsl-url>
cdcatalog.xsl.xsl (this passes $xsl-url to imported stylesheet)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="cdcatalog.xsl" />
  <xsl:variable name="xsl-url" select="xsl-url" />
  <xsl:template match="/">
    <xsl:choose>
      <xsl:when test="/xsl-url">
        <xsl:for-each select="document(substring-before(concat($xsl-url,'?'),'?'))">
          <xsl:apply-templates select="." />
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-imports />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
cdcatalog.xml (click to see result of transformation) cdcatalog.xsl (see definition and output of $xsl-url)
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl"?>
<catalog>
  <cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
  </cd>
  <cd>
    <title>The white album</title>
    <artist>Beatles</artist>
    <country>UK</country>
    <company>apple</company>
    <price>???</price>
    <year>196?</year>
  </cd>
</catalog>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="xsl-url" select="'undef'" />
  <xsl:template match="/">
    <html>
      <body>
        <h2>My CD Collection</h2>
        <table border="1">
          <tr bgcolor="#9acd32">
            <th>Title</th>
            <th>Artist</th>
          </tr>
          <xsl:for-each select="catalog/cd">
            <tr>
              <td>
                <xsl:value-of select="title" />
              </td>
              <td>
                <xsl:value-of select="artist" />
              </td>
            </tr>
          </xsl:for-each>
        </table>
        <xsl:value-of select="$xsl-url" />
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>