2

I'm currently working on a web site where we're sending down XML+XSLT to clients that support it, to save on bandwidth. However, if a client doesn't support it, we're doing the transform on the server side, and sending down the resulting HTML.

In my XSLT, I'd like to use an XPath very much like :

document('')//xsl:variable[@name='test']

(to return a node-set). This works great in both Firefox and IE, but it doesn't work with the XsltCompiledTransform- it tells me:

This operation is not supported for a relative URI.

It looks like the error is occurring in XmlUrlResolver- I know I can pass a custom one of those in, but beyond that I'm not really not sure where I should be looking. Can anyone give me any hints as to how I might get this expression working? I'm happy to use some MSXSL extensions if needed- the code would only be seen on the server side, after all.

On a more general note- is it common to do this kind of XPath query? Am I falling into some giant XSLT trap I'm not aware of? Is it going to do something crazy like slow web browsers down to a halt?

Alastair
  • 5,894
  • 7
  • 34
  • 61

3 Answers3

1

Initiate the transform using an adequately constructed instance of XsltSettings, so that the document function is allowed.

Here is an example:

// Create the XsltSettings object with the document fn allowed.
XsltSettings settings = new XsltSettings(true,false);

// Create the XslCompiledTransform object and load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("sort.xsl", settings, new XmlUrlResolver());

Your other question:

On a more general note- is it common to do this kind of XPath query? Am I falling into some giant XSLT trap I'm not aware of? Is it going to do something crazy like slow web browsers down to a halt?

The only pitfall is that this may cause the XSLT stylesheet to be re-parsed again, and this is a relatively slow operation.

More concerning is your use of the // abbreviation which is almost sure to cause performance problems.

It is much better to use this trick only for globall variables and then use this expression:

document('')/*/xsl:variable[@name='test']

Finally, in case you are not concerned with losing portability between XSLT 1.0 processors, it is more efficient to use the xxx:node-set() implementation dependent extension function to convert the RTF of the variable to a regular node-set. Here, one could use exslt:node-set() provided the XSLT processor implements EXSLT. This still achieves a relatively big degree of portability, because many XSLT processors, including XslCompiledTransform support exslt:node-set().

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Again, my fault on the original question submission- I should have mentioned that I'm already doing that. Unfortunately, the document function still doesn't like referring to itself. I've come up with a half solution that works for me, that I've posted as an answer. – Alastair Dec 10 '10 at 14:23
  • 1
    @Alastair: document('') will fail if the stylesheet is only in memory and was not loaded from a file. – Dimitre Novatchev Dec 10 '10 at 14:32
  • thanks for the updates. It all makes perfect sense. I'm flipping between use of node-set and document('') as needed, and making sure my data is using global variables. Thanks! – Alastair Dec 10 '10 at 14:42
1

I haven't managed to find a solution that allows me to use document(''), but since all I'm using it for is to get a variable to evaluate to a node-set, I'm adjusting the XML before processing on the server side, to change:

document('')//xsl:variable[@name='test']

to:

msxsl:node-set($test)

Not exactly the most graceful solution, but it works for my purposes.

Alastair
  • 5,894
  • 7
  • 34
  • 61
0

Have you tried using

document('')//xsl:variable[@name='test']

? I.e. use a zero-length string as the argument to document(), instead of passing no arguments. According to the spec, document() must have at least one argument. I'm surprised Firefox and IE are lax about that. But that could explain why XsltCompiledTransform is unhappy.

On the other hand, if XsltCompiledTransform will not support a relative URI there, then '' may not work (it is considered a relative URI). It's possible that since it's compiling the transform, it's not convenient to provide access to a tree representation of the stylesheet. "An XSLT processor is not required to support any particular URI schemes. The documentation for an XSLT processor should specify which URI schemes the XSLT processor supports."

LarsH
  • 27,481
  • 8
  • 94
  • 152