Dynamic Expression Evaluation in .Net using XSLT

March 30, 2006

Parsing and evaluating a mathematical or logical expression at runtime isn’t as easy as most people would like to think. There’s no built in .Net functionality to do it.  So, if you want to include dynamic evaluation, there are several options.

  1. Find an already-built third-party component or ActiveX control.
  2. Build your own formula string parser ala Compiler Theory and Design.  (This is something many of us did during our college days; doable but very time consuming.)
  3. Dynamically generate and compile .Net code inserting the mathematical expression into it.
  4. Last but not least, you can use XSL’s built-in parsing and expression evaluation functionality.

The fourth option has the luxury of being cheap, relatively efficient, and available in .Net today. With just a function or two, you can be using it in less than an hour.

To implement an XSLT solution, you need some XML.  In this case, the XML is meaningless and is only defined so that we have something to apply the XSL to.  For example, take the following super-simple XML:

<?xml version=”1.0″ encoding=”UTF-8″?><Root></Root>

It doesn’t get much simpler than that. Now that we have our XML, we need the XSL — also very simple.

<?xml version=”1.0″ encoding=”UTF-8″?>
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xml:space=”default” >
          <xsl:output method=”xml” version=”1.0″ encoding=”UTF-8″ indent=”yes”  standalone=”yes” omit-xml-declaration=”yes” />
          <xsl:param name=”Formula” select=”0″ />
          <xsl:template match=”/”  >
                   <xsl:value-of select=”$Formula”/>   

Looks easy, doesn’t it?  As long as the parameter passed in as “Formula” is a valid XSL expression, the XSL will calculate it and the result will be returned as text containing the value. You can even pass in a Boolean expression, like “3=4,” which will return the value “false.”  As shown in bold above, the omit-xml-declaration is important. We want the result to contain the value of the calculation without the XML header.

So how does this look inside a function?  Let’s assume we already defined a function, called “ApplyXSL,” that is designed to: accept XML and XSL strings, transform them, and return the result in a string. (In your own code, you can call your favorite XSLT functionality instead.)

Further, we will forego passing in parameters and using separate XML & XSL files in  favor of putting everything in one self-contained function (example in VB, but easily ported to C#) — like this:

Public Shared Function EvalAnyExpression(ByVal psExpression As String, ByVal psDefault As String) As String
            ‘   returns the String evaluation of the passed string
        Dim sRes As String = psDefault
        Dim sXSL As String = “”
        Const csXML As String = “<?xml version=”1.0″ ?><Root></Root>”
        Const csXSL As String = “<?xml version=””1.0″” encoding=””UTF-8″” ?>” & vbCrLf & _
                “<xsl:stylesheet version=””1.0″” xmlns:xsl=””http://www.w3.org/1999/XSL/Transform”” >” & _
                “<xsl:output method=””xml”” version=””1.0″” encoding=””UTF-8″” indent=””yes””  standalone=””yes”” omit-xml-declaration=””yes”” />” & vbCrLf & _
                “<xsl:template match=””/”” xml:space=””default”” >” & _
                “<xsl:value-of select=””EXPRESSION””/></xsl:template></xsl:stylesheet>”

            sXSL = Replace(csXSL, “EXPRESSION”, psExpression)
            sRes = ApplyXSL(csXML, sXSL)
        Catch ex As Exception
            ‘ Log the error
            ‘ and any other Error trapping functionality your application needs

        End Try
        Return sRes

    End Function

Notice how the XML and XSL are inline constants, then the EXPRESSION string is replaced with the value of the actual expression to be evaluated.

Once a formula is passed into the function, it’s inserted into the XSL, parsed, and the results are returned as a string. The resulting string can then be converted to an Int, Single, Boolean, or whatever you might be expecting from the passed formula.

This is just an example, of course, meant as a quick-start for your code.  It can be optimized in several ways, like pre-parsing the XSL and storing it in an XPath object somewhere. It could also be made more flexible, like putting the XML/XSL into files or fields in a database.