Got more questions? Find advice on: ASP | SQL | Regular Expressions | Windows
in Search
Welcome to XmlAdvice Sign in | Join | Help

Kirk Allen Evans' XML Blog

.NET From a Markup Perspective

Set Property in XsltArgumentList Extension Object: Ugly Hack

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.

Sponsor
Published Sunday, February 08, 2004 6:16 PM by kaevans
Filed under: ,

Comments

 

kaevans said:

I fully agree with Kirk that this is an ugly hack.

Something that everyone must be aware of id the danger of using extension functions with side effects in a functional language. The results may be unpredictable, difficult to explain and debug, unstable (changing from run to run).

This is why "maintaining state", "setting a property", "maintaining the order of execution" -- these are all legacy from the imperative programming world that we must try to avoid as much as possible.

I am sure that the problem of the OP can be solved without the need to set (modify) state in external objects.


Cheers,

Dimitre Novatchev [XML MVP],
FXSL developer, XML Insider,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
February 9, 2004 12:38 AM
 

kaevans said:

Thank you so much for answering my question.

It isn't a limit of understanding of the recursive nature of xslt, nor my limited understanding of applying templates which begged the question, and I resent your implication that I 'don't get XSLT'.

And frankly, if you feel dirty posting the solution then don't.

This is the type of response to an honest answer that I have come to expect from weenies. And you're not a weenie...are you?
February 9, 2004 9:24 AM
 

kaevans said:

I apologize if you feel offended in some way, that was purely unintentional. However, I stand by the points that I made in the post.

Please elaborate on your use case on how setting data in a stateful extension object yields a solution that could not better be expressed by passing a variable into a stylesheet.
February 9, 2004 9:47 AM
 

kaevans said:

Sorry - I think I over-reacted.

I get wiley when I get the 'it's wrong if you stray into a different methodology' rhetoric I get from apparent purists.

I'm working in a closed environment transforming multiple xml documents into a single document for a proprietary engine.

Working with things like dates, environment settings, and configuration information stored in a database, it is simply easier to implement using an extension object to get access to that data.

The 'setting of a variable' question came about from the need to pass to the database critera from an attribute on an xml source file to the extension object to get a proper value from the extension object during the transformation. Granted, this could be accomplished via a function with a parameter. The question came more from an academic standpoint than a anything else.

I still don't like 'variables' in XSLT's. They seem more like 'constants'.

At any rate, my opinion of your book is still in good standing and I still recommend it!
February 9, 2004 10:33 AM
 

kaevans said:

If you need access to environment variables, then the best case is to pass the desired information into the stylesheet as a parameter.

As for the transformation of multiple documents to a single result, I imagine that you have looked at the document() function... you can combine that approach with a custom XmlResolver for a very powerful solution, allowing multiple inputs for XSLT transformations.
February 9, 2004 10:56 AM
 

TrackBack said:

February 8, 2004 9:40 PM
 

TrackBack said:

Trackback from Steven Livingstone's blog
February 16, 2004 4:04 PM
Anonymous comments are disabled

This Blog

Syndication

News

Looking for a place to talk about XML? Tired of the "main feed police" cracking about your interests in football and politics? Sign up for a free web log on XMLAdvice.com.