I have run into an instance where I need to terminate and raise an exception from within an XSLT template, based on values (or lack thereof) within the source document. The XSLT transform is running within a BizTalk map.
The secret is the following little-known XSLT construct, which can be conditionally called at any point in the transform:
<xsl:message terminate="yes">Custom error text</xsl:message>
This will cause the XSLT engine to stop processing immediately, and raise an exception. This exception, including the custom error text contained within the message segment, can be caught in the BizTalk Orchestration engine by explicitly catching an exception of type Microsoft.XLANGS.BaseTypes.TransformationFailureException.
A quick xslt template to left pad a value:
<xsl:template name="prepend-pad"> <!-- recursive template to right justify and prepend the value with whatever padChar is passed in --> <xsl:param name="padChar"> </xsl:param> <xsl:param name="padVar"/> <xsl:param name="length"/> <xsl:choose> <xsl:when test="string-length($padVar) < $length"> <xsl:call-template name="prepend-pad"> <xsl:with-param name="padChar" select="$padChar"/> <xsl:with-param name="padVar" select="concat($padChar,$padVar)"/> <xsl:with-param name="length" select="$length"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="substring($padVar,string-length($padVar) - $length + 1)"/> </xsl:otherwise> </xsl:choose> </xsl:template>
I recently had a chicken-and-egg request from a customer.
They wanted to be able to see how their data would appear after being processed by their BizTalk orchestration, but without actually passing the data through the orchestration (as this would change the state in their database). Complicating this, the outgoing data is processed by a set of Policies using the Business Rules Engine (BRE).
Here’s the steps I undertook:
- Generate a strongly-typed version of the target schema. This is done using the xsd.exe tool included in the Visual Studio SDK.
xsd.exe biztalktalk.targetschema.xsd /class /namespace:http://biztalktalk.targetnamespace/22.214.171.124/
Include the resultant .cs file in your project.
- First thing is to apply the Business Rules to the source document. This mirrors the approach we’ve taken through the Orchestration.
- In code, we create an instance of the Rules Engine:
TypedXmlDocument typedDoc = new Microsoft.RuleEngine.TypedXmlDocument(document, docType); Policy pol = new Policy(ruleName); pol.Execute(typedDoc); pol.Dispose();
Where document is the source document, and docType is the fully qualified document type (i.e. AssemblyName.ClassName) of the source document.
- If you have multiple rules in multiple policies, you will need to set-up (and dispose) a new Policy object for each rule-set.
- The above step makes changes directly to the wrapped “document” XML document. After this step, you can use the old document with the Business Rule changes applied.
Now we want to format the source document according to the destination schema. We currently do this in BizTalk using a map, so rather than replicate our development efforts, and possibly introducing errors, we will “re-use” the BizTalk map from our .Net code.
- Right click on your map file in Visual Studio, and select “Validate Map”. In the output pane, there will be a link saying “… The output XSLT is stored in the following file: <file://…” The file at this location contains the valid XSLT representation of your BizTalk map.
- Copy the .xsl file into the same directory as your solution, and include it in your project.
- Next, use the XSLT to transform the initial document into the format defined by the XSD in the first step. I’ll write more about this later, but for now, this site is your friend.
Now we have an Xml Document in the expected destination format, with all BRE rules applied. You can bind to this document in an ASP.NET DataGrid, and away you go.