Search code examples
c#xsltmsxsl

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


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?


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