Paul Duncan asks in the microsoft.public.xsl list how to set a property for an XSLT extension object. Yes, there is a way to do set the property of an XSLT extension object in .NET. But...
This is such an ugly hack, I feel dirty posting the solution.
First, the XSLT transformation that allows the user to set a property in an XSLT extension object. Note that I use an xsl:variable to contain the result of the method call. This allows me to store the method return without including it in the XSLT result tree. I also named the call with “set_“, accessing the property setter as a method.
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:user="urn:net-xmlandasp:examples">
<xsl:template match="/">
<xsl:variable name="foo" select="user:set_MyProperty(.)"/>
<xsl:value-of select="user:SayHello()"/>
</xsl:template>
</xsl:stylesheet>
Here is the C# code for providing the extension object to the XslTransform.Transform method:
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
namespace XMLAdvice
{
class UglyXSLTHackTester
{
[STAThread]
static void Main(string[] args)
{
XslTransform trans = new System.Xml.Xsl.XslTransform();
trans.Load(@"C:\temp\XSLTFile1.xslt");
XPathDocument doc = new XPathDocument(@"C:\temp\XMLFile1.xml");
System.Xml.Xsl.XsltArgumentList xslArgs = new System.Xml.Xsl.XsltArgumentList();
MyExtension extension = new MyExtension();
xslArgs.AddExtensionObject("urn:net-xmlandasp:examples",extension);
trans.Transform(doc,xslArgs,Console.Out,null);
}
}
public class MyExtension
{
private string _myProp;
public string MyProperty
{
get{return _myProp;}
set {_myProp = value;}
}
public string SayHello()
{
return string.Format("Hello, {0}",_myProp);
}
}
}
Given the input XML document:
<?xml version="1.0" encoding="utf-8" ?>
<root>Kirk Allen Evans</root>
The output to the console is:
Hello, Kirk Allen Evans
XSLT is not designed to store interim state. It is explicitly a language for reading documents from a tree source and transforming them to a result tree where the transformation processing is side-effect-free. Each transformation of the source document should produce the exact same result each time the process is run. This is why concepts of “current-date“ and “current-user“ are not explicitly provided in XSLT (additionally, concepts may not be portable across platforms).
If you set a stateful variable in script or in an extension object, you cannot tell when the variable would be set, nor could you tell how many times the variable would be set or evaluated. For a background on why this is such an ugly hack, see Julian Reschke’s response to a similar thread on setting variables within XSLT . Julian’s response to the thread shows that processing changed between MSXML3 and MSXML4, proving that the facility of setting stateful variables should not be relied upon and the behavior of which is not specified in the XSLT 1.0 spec. Taking advantage of the behavior under one processor does not guarantee that the behavior will remain in newer versions of the same processor.
Ed Note: For those just itching to know, the value under .NET 1.1 would be “321“. I have not tested with Whidbey to see if the behavior remains or will produce “123“.
The fact that I had to rely on a hack like setting an XSLT variable indicates the limitied utility of this approach. You can only set the value of the XSLT variable once, you cannot set the value again within the scope of the variable’s declaration. You are much better off simply passing a parameter to a stateless method in your extension object to retrieve a value. In fact, you could use a parameter to create a result tree fragment and pass that to the extension object's method for further processing, keeping state within the XSLT transformation where the behavior is specified. In short, design your object to be stateless, exposing only methods that return values.
Now that I have stated the correct means of using an extension object, let me go one step further: most reasons why XSLT developers use extension objects is due to their limited understanding of the recursive nature of XSLT and their limited understanding of the concept of applying templates. Spend the time reading about XSLT before applying it, and your XSLT programming life will be much simpler. There are situations where XSLT stands to be enhanced to increase developer productivity... and the developer should investigate technologies like EXSLT and FXSL to make informed decisions about how best to utilize XSLT.