How can I use the XPath expression “document('')” in a .NET XsltCompiledTransform? Should I?

StackOverflow https://stackoverflow.com/questions/4405622

  •  25-09-2019
  •  | 
  •  

Question

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?

Was it helpful?

Solution

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().

OTHER TIPS

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.

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."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top