I’m not sure if this is actually of any use to anyone but if you do want to use Microsoft’s
Extended XPath Functions from a BizTalk Map (see my previous
post) then I’ve created a wrapper assembly to do this for you.
Method names are the same as the original functions, but using “_” instead
of “-“.
Method |
Description |
|
format_date |
Formats an XSD dateTime value into a date string using the given format string and culture |
|
Usage: |
format_date(dateTime, [lang], [format]) |
|
|
dateTime: string containing XSD dateTime value lang: Optional culture string – if blank or not supplied then current culture is used format: Optional date format string (same format as DateTime.ToString(string)) – if blank or not supplied then default date format is used |
|
Example: |
format_date(‘2000-02-16T15:56:00+02:00’, ”, ‘MMM dd, yyyy’) |
|
format_time |
Formats an XSD dateTime value into a time string using the given format string and culture |
|
Usage: |
format_time(dateTime, [lang], [format]) |
|
|
dateTime: string containing XSD dateTime value lang: Optional culture string – if blank or not supplied then current culture is used format: Optional time format string (same format as DateTime.ToString(string)) – if blank or not supplied then default time format is used |
|
Example: |
format_date(‘2000-02-16T15:56:00+02:00’, ”, ‘hh mm ss’) |
|
local_name |
Strips a namespace or namespace prefix from a node name |
|
Usage: |
local_name(nodeName) or local_name(node) |
|
|
nodeName: qualified node name (e.g. as supplied by name() expression) node: XPathSelectionIterator object, what you get when you select a node in a map via XSLT |
|
Example: |
local_name(‘ns0:root’) |
|
namespace_uri |
Looks up the namespace for a given namespace-prefix |
|
Usage: |
namespace_uri(nodeName, currentNode) namespace_uri(nodeName, xmlFragment) namespace_uri(nodeName, list) |
|
|
nodeName: prefixed node name currentNode: XPathSelectionIterator object referencing the current node xmlFragment: fragment of xml, supplied as a string list: list containing a single XPathItem |
|
Example: |
namespace_uri (‘ns0:root’, current()) |
|
number |
Converts a given string into a double number. Supports Exponential and INF statements |
|
Usage: |
number(value) |
|
|
value: string to be converted to a double. Can also be exponential (i.e. ‘1e023’, or ‘-INF’ or ‘INF’) |
|
Example: |
number(‘INF’) |
|
string_compare |
Compares two strings, with optional case/culture sensitivity |
|
Usage: |
string_compare(s1, s2, [lang], [options]) |
|
|
s1: first string to compare s2: second string to compare lang: Culture to use for comparison – if blank or not supplied then current culture is used options: ‘u’: case-sensitive, uppercase-first comparison ‘i’: case-insensitive comparison ” (or not supplied): case-sensitive, lowercase-first comparison |
|
Example: |
string_compare(‘the brown cow’, ‘The Brown Cow’, ”, ‘u’) Note: the return value is same as for String.Compare() in C#. |
|
utc |
Converts an XSD dateTime value into coordinated universal time (i.e. GMT) |
|
Usage: |
utc(dateTime) |
|
|
dateTime: string containing XSD dateTime value |
|
Example: |
utc(‘2000-02-16T15:56:00+02:00’) |
Note: the following methods are not in this class
The reason for this is that these functions are not implemented in System.Data.SqlXml.dll –
they’re in MSXML.
Admittedly they’d be fairly easy to implement, but the purpose of this wrapper is
to expose the functions in the XsltFunctions class
in System.Data.SqlXml.dll.
The source is fully documented, so hopefully it’s clear(ish) how to use the helper
class.
Notes on implementation
For all but two of the functions, I just call the corresponding method in XsltFunctions (providing
some method overloads).
However namespace_uri() and number() are
different.
The signatures for these methods in XsltFunctions are:
public static string MSNamespaceUri(string name, XPathNavigator currentNode)
public static double MSNumber(IList<XPathItem>
value)
In order to use these from a BizTalk Map, I added some method overloads which can
call the above methods with the correct parameter types.
Installation Instructions
Just add the DLL to the GAC (it’s already signed) or build the source code project,
and then GAC the compiled assembly.
Note: this version is compiled against v2.0.50727.1433 of System.Data.SqlXml.dll –
if you have a different version of System.Data.SqlXml.dll then
you’ll need to add a reference to your version, and re-compile the project.
Problems with the Script Functoid
If you’ve ever tried to pass a node to an external assembly using the script functoid,
you’ve probably already noticed something: the script functoid explicitly converts
all input parameters to strings by wrapping a string() expression
around the parameters.
For example, if you do this:
(i.e. use a record as the input parameter to a script functoid) then you’ll soon discover
that the Mapper always assumes that you want the value of the node, not the node
itself. And it therefore helpfully wraps the node in a string() expression
(adding a text() expression
if necessary):
<xsl:variable name=”var:v5″
select=”ScriptNS0:namespace_uri(string(./text()))” />
So the only way to pass a node/element as a parameter is to use custom XSLT in a script
functoid – an example of this is provided below.
Examples of Usage
Using functions where all parameters are strings
For example, using format_date().
Add the System.Data.SqlXmlHelper.dll as
a reference to your BizTalk project.
In a BizTalk Map, add a script functoid, choose External Assembly as the Script
Type, and then choose the System.Data.SqlXmlHelper assembly,
and the System.Data.SqlXmlHelper.Helper class.
Next choose the method you wish to use, such as the format_date method:
Next, add some inputs to the script functoid – in this example, I’ve used constants
for the inputs, but they could easily be links from other nodes:
Now, just link the output of your script functoid to a node on the destination schema.
And that’s it!
Using functions where you need an XPathNodeIterator parameter
namespace_uri is an
example of an expression that needs context i.e. a current node to process.
In this case, the only way to pass a current node to the method is via custom XSLT
in a script functoid.
You can do this by using an XSLT expression such as this one in a Custom XSLT script
functoid
Note: the above example assumes that the ScriptNS0 prefix
is already defined in the map and linked to an Extension Object for the System.Data.SqlXmlHelper.dll assembly.
This will be true if you already have a script functoid using System.Data.SqlXmlHelper.dll as
an external assembly in the same map.
If you don’t, then you’ll need to generate a separate ExtensionObjects xml file and
put this in it:
You will also need to manually add a definition for the script namespace prefix to
the custom XSLT e.g.
(although you will probably want to use a separate prefix than ScriptNS0 as
you could clash with any prefix added later)
Download the code
You can download the assembly and full source code here.
The source code solution includes a BizTalk test project with a sample map in it.
System.Data.SqlXmlHelper.dll
(20 KB)
System.Data.SqlXmlHelper
Source Code.zip (16.71 KB)
(Note: in the sample BizTalk project, you right-click the sample map and choose
Test Map to see the results – if you get an error make sure you have GACced the System.Data.SqlXmlHelper.dll assembly).
Testing the sample map
Included in the BizTalk solution is a sample map which demonstrates execution of all
the functions:
In order to use this map, you’ll need to change the TestMap Input Instance property
to point at the SqlXmlHelperTest_Instance.xml file (located in the SampleXML folder
of the BizTalk project).
The map takes this input:
And transforms it to this output:
(Note: the pattern used for format_date is
“MMM dd, yyyy”, and the pattern for format_time is
“hh/mm/ss”)
Let me know if you find it useful.