Click here to Skip to main content
13,556,130 members
Click here to Skip to main content
Add your own
alternative version


16 bookmarked
Posted 2 Mar 2003

Adding custom XPath functions to XSL

, 2 Mar 2003
Rate this:
Please Sign up or sign in to vote.
This article shows you how to add context aware XPath functions to an XSL transformation. This is done by a hack using reflection.


The XSL transformation is a powerful way of visualizing XML. The presence of extension objects makes it even more powerful. However it turns out that extension objects are very limited. They have no way of retrieving the current context of the transformation or the current document. Furthermore their return type is limited to only numbers and strings (returning an IXPathNavigable is restricted. See here for more details). This article presents a work around for the first problem.

Why use context aware XPath functions

A simple but very powerful application of such is the eval function. It evaluates XPath queries contained in a string or variable. For example imagine you have the following:

<xsl:variable name='vTest'>123456</xsl:variable>
<xsl:variable name= 'vQuery'>$vTest</xsl:variable>

If you take the value of vQuery using xsl:value-of you would get $vTest as a result. On the other hand <xsl:value-of select='eval($vTest)'/> will evaluated to 123456. There is no such function built-in so we will write it our selves.


To read this article you should have good knowledge in C# and the Microsoft's .NET XML parser.

How it works

It looks like Microsoft have had the idea of allowing the user to write context aware functions. Have a look at the 2 classes IXsltContextFunction and XsltContext in the System.Xml.Xsl namespace. You can make your own context and function classes derived from the above 2, but you can use them only in programmatic XPath queries. An article I found in Microsoft's KB "recomends" that you use extension objects instead of IXsltContextFunction derived classes for writing your own XPath functions. Well actually it turns out that this not a recommendation - it is the only way to do it. There is no way of adding a context aware XPath extension function to the transformation. I decompiled the code that resolves functions in an XSLT (System.Xml.Xsl.XsltCompileContext.ResolveFunction) an here is what I got:

public virtual IXsltContextFunction ResolveFunction(string prefix, 
              string name, System.Xml.XPath.XPathResultType[] argTypes){
    IXsltContextFunction local0;
    string local1;
    object local2;
    MethodInfo local3;

    local0 = null;
    if (prefix == String.Empty)
        local0 = XsltCompileContext.s_FunctionTable.get_Item(name) 
                                           as IXsltContextFunction;
    else {
        local1 = this.LookupNamespace(prefix);
        if (local1 == "urn:schemas-microsoft-com:xslt" && name == "node-set")
            local0 = XsltCompileContext.s_FuncNodeSet;
        else {
            local3 = this.GetExtentionMethod(local1, name, argTypes, local2);
            if (local2 == null)
                throw new XsltException("Xslt_ScriptInvalidPrefix", prefix);
            if (local3 != null)
                local0 = new FuncExtension(local2, local3);
    if (local0 == null)
        throw new XsltException("Xslt_UnknownXsltFunction", name);
    if ((int) argTypes.Length < local0.Minargs || 
             local0.Maxargs < (int) argTypes.Length)
        throw new XsltException("Xslt_WrongNumberArgs", name, 
                       Convert.ToString((int) argTypes.Length));
    return local0;

As you can see there are 3 types of functions that the XSLT can resolve:

  • Ones that are in the root XML namespace
  • The msxsl:node-set function
  • Functions on extension objects

From the code above, it is visible that the only way of inserting a context aware function is to put it in the static hashtable s_FunctionTable field. As you have already guessed the System.Xml.Xsl.XsltCompileContext is a protected class and so is the s_FunctionTable. To access it, we will use reflection:

static Hashtable XslFunctionTable
        Assembly xmlAssembly = Assembly.LoadWithPartialName("System.Xml");
        Type tXsltCompileContext = xmlAssembly.GetType
        FieldInfo finf = tXsltCompileContext.GetField("s_FunctionTable", 
                           BindingFlags.NonPublic | BindingFlags.Static);
        return finf.GetValue(null) as Hashtable;

Once we have the hash table we can easily add or remove functions from it. The hashtable is initialized in the static constructor of System.Xml.Xsl.XsltCompileContext so we should avoid adding and removing functions in static constructors


This is actually a hack. It works fine on .NET framework 1.0 but it may not work in future releases of the framework. I hope Microsoft fixes this problem in future. Also you can add functions only in the root XML namespace.

Possible improvements

The System.Xml assembly is located using it's partial name. This is not good because future versions of the .NET framework will use newer XML parsers and the hack wont work. The full name should be used instead.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Stefan Popov
Germany Germany
No Biography provided

You may also be interested in...

Comments and Discussions

General.NET 2.0 / XslCompiledTransform Pin
Caledonia7-Dec-06 14:54
memberCaledonia7-Dec-06 14:54 
GeneralRe: .NET 2.0 / XslCompiledTransform Pin
Stefan Popov15-Dec-06 1:02
memberStefan Popov15-Dec-06 1:02 
GeneralNo Hack Needed Pin
Heath Stewart4-Mar-03 8:11
editorHeath Stewart4-Mar-03 8:11 
GeneralRe: No Hack Needed Pin
Stefan Popov5-Mar-03 4:39
memberStefan Popov5-Mar-03 4:39 
GeneralRe: No Hack Needed Pin
Robert te Kaat24-Nov-09 2:19
memberRobert te Kaat24-Nov-09 2:19 
GeneralRe: No Hack Needed Pin
Stefan Popov24-Nov-09 15:11
memberStefan Popov24-Nov-09 15:11 
GeneralRe: No Hack Needed Pin
Robert te Kaat25-Nov-09 10:34
memberRobert te Kaat25-Nov-09 10:34 
Questionlocal0 and local1 ? Pin
Masaaki Onishi4-Mar-03 5:22
memberMasaaki Onishi4-Mar-03 5:22 
AnswerRe: local0 and local1 ? Pin
Stefan Popov5-Mar-03 4:21
memberStefan Popov5-Mar-03 4:21 
GeneralWell done! Pin
Carel3-Mar-03 22:54
memberCarel3-Mar-03 22:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03-2016 | 2.8.180515.1 | Last Updated 3 Mar 2003
Article Copyright 2003 by Stefan Popov
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid