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.
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=”/” >
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”” >” & _
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
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.