Whenever I’ve looked at the XSLT generated by a map I’ve always been confused by the amount of inline C# generated by these functoids.
After the String Functoids I’d say that these are the next most widely used and yet
all but one of them has an XSLT v1.0 equivalent!
The code emitted for “Logical Equal” always makes me laugh – 12 lines of C# code can
be replaced by… (wait for it)… one “=” symbol!
For each functoid I’ve shown:
- Whether XSLT or C# is emitted
- Whether an XSLT equivalent exists
- The XSLT or C# emitted by the functoid
-
Where C# is emitted, the equivalent XSLT to achieve the same functionality (in both
XSLT v1.0 and v2.0)
Functoids covered in this category:
Equal | Logical Existence |
Greater Than | Logical NOT |
Greater Than or Equal To | Logical Numeric |
IsNil | Logical OR |
Less Than | Logical String |
Less Than or Equal To | Not Equal |
Logical Date | Common Code |
This is the fifth in a series of 13 posts about the BizTalk Mapper.
The other posts in this series are (links will become active as the posts become active):
Understanding
the BizTalk Mapper: Part 1 – Introduction
Understanding
the BizTalk Mapper: Part 2 – Functoids Overview
Understanding
the BizTalk Mapper: Part 3 – String Functoids
Understanding
the BizTalk Mapper: Part 4 – Mathematical Functoids
Understanding the BizTalk Mapper: Part 5 – Logical Functoids
Understanding the BizTalk Mapper: Part 6 – Date/Time Functoids
Understanding the BizTalk Mapper: Part 7 – Conversion Functoids
Understanding the BizTalk Mapper: Part 8 – Scientific Functoids
Understanding the BizTalk Mapper: Part 9 – Cumulative Functoids
Understanding the BizTalk Mapper: Part 10 – Database Functoids
Understanding the BizTalk Mapper: Part 11 – Advanced Functoids
Understanding the BizTalk Mapper: Part 12 – Performance and Maintainability
Understanding the BizTalk Mapper: Part 13 – Is the Mapper the best choice for Transformation
in BizTalk? When all of the above have been posted, the entire series will
be downloadable as a single Microsoft Word document, or Adobe PDF file.
Logical Functoids |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalEq(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 == d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) == 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “=” operator e.g. value = value |
||
XSLT 2.0 Equivalent: Use the “=” operator e.g. value = value Note: Both the C# version and the XSLT version will perform a case-sensitive comparison. |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalGt(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 > d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) > 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “>” operator e.g. value > value |
||
XSLT 2.0 Equivalent: Use the “>” operator e.g. value > value |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalGte(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 >= d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) >= 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “>=” operator e.g. value >= value |
||
XSLT 2.0 Equivalent: Use the “>=” operator e.g. value >= value |
||
|
|
|
Generates: XSLT |
Has XSLT Equivalent: N/A |
|
Emitted Code: string(node/@xsi:nil) = ‘true’ |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalLt(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 < d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) < 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “<” operator e.g. value < value |
||
XSLT 2.0 Equivalent: Use the “<” operator e.g. value < value |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalLte(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 <= d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) <= 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “<=” operator e.g. value <= value |
||
XSLT 2.0 Equivalent: Use the “<=” operator e.g. value <= value |
||
|
Logical AND |
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalAnd(string param0, string param1) { return ValToBool(param0) && ValToBool(param1); return false; } |
||
XSLT 1.0 Equivalent: Use the “and” operator e.g. expression and expression |
||
XSLT 2.0 Equivalent: Use the “and” operator e.g. expression and expression |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: No |
|
Emitted Code: public bool LogicalIsDate(string val) { return IsDate(val); } |
||
XSLT 1.0 Equivalent: (none) |
||
XSLT 2.0 Equivalent: (none) Note: an XPath expression could be created using the dateTime function, but would require parsing out separate date/time portions. There are other implementations available on the internet, but none of them are trivial. XPath 1.0 has no native DateTime functionality built in. |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalExistence(bool val) { return val; } Note: The above method may seem a bit strange, but it makes sense if you understand that you test for existence of a node in XSLT by using the boolean() function, and passing a node (or any sort of value). The XSLT generated by the Logical Existence functoid wraps the boolean() function round the value passed to the LogicalExistence method like this: userC#:LogicalExistence(boolean(@name)) (where @name was an attribute that we connected to the Logical Existence functoid). |
||
XSLT 1.0 Equivalent: boolean(node) |
||
XSLT 2.0 Equivalent: boolean(node) |
||
|
|
|
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalNot(string val) { return !ValToBool(val); } |
||
XSLT 1.0 Equivalent: not(expression) |
||
XSLT 2.0 Equivalent: not(expression) |
||
|
||
Generates: C# |
Has XSLT Equivalent: No |
|
Emitted Code: public bool LogicalIsNumeric(string val) { return IsNumeric(val); } |
||
XSLT 1.0 Equivalent: (none) |
||
XSLT 2.0 Equivalent: (none) Note: You can achieve this through use of a statement such as: string(number(value)) != ‘NaN‘ Or in XPath 2.0 using a statement such as: value castable as xs:decimal |
||
|
||
|
||
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: Note: there will be one overload per unique number of parameters. Here we show an example with two input parameters. public bool LogicalOr(string param0, string param1) { return ValToBool(param0) || ValToBool(param1); return false; } |
||
XSLT 1.0 Equivalent: Use the “or” operator e.g. ((expression or expression) |
||
XSLT 2.0 Equivalent: Use the “or” operator e.g. ((expression or expression) |
||
|
||
Generates: C# |
Has XSLT Equivalent: No |
|
Emitted Code: public bool LogicalIsString(string val) { return (val != null && val != “”); } |
||
XSLT 1.0 Equivalent: (none) |
||
XSLT 2.0 Equivalent: (none) Note: the same thing can be achieved with an XPath expression. |
||
|
||
|
||
Generates: C# |
Has XSLT Equivalent: in 1.0 and 2.0 |
|
Emitted Code: public bool LogicalNe(string val1, string val2) { bool ret = false; double d1 = 0; double d2 = 0; if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2)) { ret = d1 != d2; } else { ret = String.Compare(val1, val2, StringComparison.Ordinal) != 0; } return ret; } |
||
XSLT 1.0 Equivalent: Use the “!=” operator e.g. (value != value) |
||
XSLT 2.0 Equivalent: Use the “!=” operator e.g. (value != value) | ||
|
||
Common Code (this is common code used by all the logical functoids) |
||
public bool IsNumeric(string val) { if (val == null) { return false; } double d = 0; return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d); } public bool IsNumeric(string val, ref double d) { if (val == null) { return false; } return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d); } public bool IsDate(string val) { bool retval = true; try { DateTime dt = Convert.ToDateTime(val, System.Globalization.CultureInfo.InvariantCulture); } catch (Exception) { retval = false; } return retval; } public bool ValToBool(string val) { if (val != null) { if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0) { return true; } if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0) { return false; } val = val.Trim(); if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0) { return true; } if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0) { return false; } double d = 0; if (IsNumeric(val, ref d)) { return (d > 0); } } return false; } |