tags:

views:

31

answers:

2

Using XSLT 1.0, I'm trying to essentially create a small node set and then pass it as a parameter to a template, something like the following:

<xsl:call-template name="widget">
  <xsl:with-param name="flags">
    <items>
      <item>widget.recent-posts.trim-length=100</item>
      <item>widget.recent-posts.how-many=3</item>
      <item>widget.recent-posts.show-excerpt</item>
    </items>
  </xsl:with-param>
</xsl:call-template>

The idea is that then from within the widget template I could write something like:

<xsl:value-of select="$flags/item[1]" />

Obviously I get compile errors.. how can I achieve this sort of thing?

+1  A: 

Well, I managed to get around this in the following way:

First add a custom namespace to your stylesheet, e.g. xmlns:myns="http://my.ns.com"

Then define the nodeset at the top of the stylesheet:

<myns:recent-posts-flags>
    <item>widget.recent-posts.trim-length=100</item>
    <item>widget.recent-posts.how-many=3</item>
    <item>widget.recent-posts.show-excerpt</item>
</myns:recent-posts-flags>

Then reference in the following way:

<xsl:call-template name="widget">
    <xsl:with-param name="flags" select="document('')/*/myns:recent-posts-flags" />
</xsl:call-template>

This works, but it would still be ideal for me to define the node-set within the <xsl:with-param> tag itself, as in the first example I gave.. anyone think that would be possible?

John J. Camilleri
+1 This is FAQ and also in the [specs](http://www.w3.org/TR/xslt#stylesheet-element): `In addition, the xsl:stylesheet element may contain any element not from the XSLT namespace, provided that the expanded-name of the element has a non-null namespace URI. (...) Such elements can provide, for example, information used by extension elements or extension functions, information about what to do with the result tree, information about how to obtain the source tree, metadata about the stylesheet, structured documentation for the stylesheet.`
Alejandro
+1  A: 

There is a way (non-standard) in XSLT 1.0 to create temporary trees dynamically and evaluate XPath expressions on them, however this requires using the xxx:node-set() function.

Whenever nodes are dynamically created inside the body of an xsl:variable or an xsl:param, the type of that xsl:variable / xsl:param is RTF (Result Tree Fragment) and the W3 XSLT 1.0 Spec. limits severyly the kind of XPath expressions that can be evaluated against an RTF.

As a workaround, almost every XSLT 1.0 vendor has their own xxx:node-set() extension function that takes an RTF and produces a normal node-set from it.

The namespace to which the xxx prefix (or any other prefix you choose) is bound is different for different vendors. For MSXML and the two .NET XSLT processor it is: "urn:schemas-microsoft-com:xslt". The EXSLT library uses the namespace: "http://exslt.org/common". This namespace EXSLT is implemented on many XSLT 1.0 processors and it is recommended to use its xxx:node-set() extension, if possible.

Here is a quick example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 xmlns:ext="http://exslt.org/common"
  exclude-result-prefixes="ext msxsl"
 >
 <xsl:template match="/">
  <xsl:variable name="vTempRTF">
   <a>
    <b/>
   </a>
  </xsl:variable>

  <xsl:copy-of select="ext:node-set($vTempRTF)/a/*"/>
 </xsl:template>
</xsl:stylesheet>
Dimitre Novatchev
Just what I needed, thanks! +1
John J. Camilleri