This post is a continuation to the Schematron validation using XSLT in BizTalk blog series
The source code for this blog post has been uploaded in the below location
http://code.msdn.microsoft.com/Schematron-validation-b4d892ee
So, How to do schematron validation using XSLT in BizTalk?
High level steps
1. Define the schematron rules in the .sch file
2. Use XSLT processor(MSXSL) and pass the Rules.sch file and the Conformance1-5.xsl file
3. STEP 2 would produce a Validating XSLT file, let’s call Valdating.xsl.
4. Use XSLT processor and pass the XML document and Validating.xsl. This would produce the final schematron results.
Pros of using this approach
1. There is no dependency with any third party library
2. The schematron skeleton XSLT template that we use is ISO standard, open source and is used widely in various companies.
3. Complete use of XSLT functions like document(), key() etc.
Cons of using this approach
1. Compared to the XPATH implementation it is slower, as there is an additional step of preparing the validating XSLT.
2. The initial setup is a bit complex, but when you have setup the Pipeline components and required schemas and Schematron Skeleton XSLTs, then it is easier.
Detailed Implementation
We have seen the high level steps and now it’s time to get down deep into the implementation details.
Before going into the implementation, let’s take a scenario, so that we can use that for our implementation
A manufacturing company has adopted an e-Commerce solution by integrating its services with its client. Its clients can send purchase order by placing the files in a FILE folder. The Manufacturing Company is responsible for validating the structure of the message before processing the Purchase Order.
We need to have a consistent approach for validating the semantics of the schema and report any errors. We will go step in step in implementing this solution.
1. Define the PurchaseOrder schema
Below is the high level structure of the schema.
Please also check the schema file from the below link.
http://code.msdn.microsoft.com/Schematron-validation-b4d892ee
Okay, we have defined the schema. The next step would be writing schematron rules.
2. Define schematron rules
To start with, we will define quite simple schematron rules.
Schematron schema has a predefined structure. Below is the skeleton structure of the schematron.
<?xml version=”1.0″ encoding=”UTF-8″?>
<sch:schema xmlns:sch=”http://www.ascc.net/xml/schematron” xmlns:xs=”http://www.w3.org/2001/XMLSchema” queryBinding=”xslt2″
</sch:schema>
We will add the namespace to it.
<sch:ns uri=” http://www.nmstech.uk/ecommerce/schemas/v01 ” prefix=”nms” />
And we will add a very simple rule
<sch:pattern name=”Check Existence”>
<sch:rule context=”nms:PurchaseOrder”>
<sch:assert test=”nms:Id”>PurchaseOrder Id is missing or cannot be empty</sch:assert>
</sch:rule>
</sch:pattern>
Let’s put it together.
<?xml version=”1.0″ encoding=”UTF-8″?>
<sch:schema xmlns:sch=”http://www.ascc.net/xml/schematron” xmlns:xs=”http://www.w3.org/2001/XMLSchema” queryBinding=”xslt2″ >
<sch:ns uri=” http://www.nmstech.uk/ecommerce/schemas/v01 ” prefix=”nms” />
<sch:pattern name=”Check Existence”>
<sch:rule context=”nms:PurchaseOrder”>
<sch:assert test=”nms:Id”>PurchaseOrder Id is missing</sch:assert>
</sch:rule>
</sch:pattern>
</sch:schema>
That’s it; we have got a very simple schematron schema.
3. Define schema to populate error information
When we run the XSLT processor with conformance1-5.xslt, we will get a schematron-output message with all the error information. We will use the same structure to define a schema, so that we can apply an inbound map to transform this into a more meaningful message or transform this to a client response message.
4. Download Schematron Skeleton XSLTs
The conformance1-5.xsl and the skeleton1-5.xsl has been provided by Academia Sinica Computing Center, Taiwan
As already said, the above XSLTs are open source and can be downloaded from
http://xml.ascc.net/schematron/1.5/skeleton1-5.xsl
http://xml.ascc.net/schematron/1.5/conformance1-5.xsl
5. Download MSXSL 3.0 for testing purpose
Download the command line utility MSXSL 3.0 for testing purpose. In the actual development we will use the BTSXslTransform class to apply the XSLTs.
6. Generate Validating XSLT using XSLT processor and Skeleton XSLTs
Execute the below to generate the validating XSLT
msxsl -o PO-Validating.xsl PurchaseOrder.sch conformance1-5.xsl
Below is the auto generated Validating XSLT
<?xml version=”1.0″ encoding=”UTF-16″ standalone=”yes”?>
<xsl:stylesheet version=”1.0″ nms:dummy-for-xmlns=”” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:sch=”http://www.ascc.net/xml/schematron” xmlns:nms=” http://www.nmstech.uk/ecommerce/schemas/v01 “>
<xsl:output method=”xml” omit-xml-declaration=”no” standalone=”yes” indent=”yes” />
<xsl:template match=”*|@*” mode=”schematron-get-full-path”>
<xsl:apply-templates select=”parent::*” mode=”schematron-get-full-path” />
<xsl:text>/</xsl:text>
<xsl:if test=”count(. | ../@*) = count(../@*)”>@</xsl:if>
<xsl:value-of select=”name()” />
<xsl:text>[</xsl:text>
<xsl:value-of select=”1+count(preceding-sibling::*[name()=name(current())])” />
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match=”/”>
<schematron-output title=”” schemaVersion=”” phase=”#ALL”>
<ns uri=” http://www.nmstech.uk/ecommerce/schemas/v01 ” prefix=”nms” />
<active-pattern name=”Check Existence”>
<xsl:apply-templates />
</active-pattern>
<xsl:apply-templates select=”/” mode=”M1″ />
</schematron-output>
</xsl:template>
<xsl:template match=”nms:PurchaseOrder” priority=”4000″ mode=”M1″>
<fired-rule id=”” context=”nms:PurchaseOrder” role=”” />
<xsl:choose>
<xsl:when test=”nms:Id” />
<xsl:otherwise>
<failed-assert id=”” test=”nms:Id” role=””>
<xsl:attribute name=”location”>
<xsl:apply-templates select=”.” mode=”schematron-get-full-path” />
</xsl:attribute>
<text>PurchaseOrder Id is missing</text>
</failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode=”M1″ />
</xsl:template>
<xsl:template match=”text()” priority=”-1″ mode=”M1″ />
<xsl:template match=”text()” priority=”-1″ />
</xsl:stylesheet>
Below is a sample PurchaseOrder instance
<?xml version=”1.0″ encoding=”UTF-8″?>
<!–Sample XML file generated by XMLSpy v2011 (http://www.altova.com)–>
<nms:PurchaseOrder xsi:schemaLocation=”http://www.nmstech.uk/ecommerce/schemas/v01 PurchaseOrder.xsd” xmlns:nms=”http://www.nmstech.uk/ecommerce/schemas/v01″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<nms:Timestamp>2001-12-17T09:30:47Z</nms:Timestamp>
<nms:POHeader>
<nms:SoldTo>
<nms:PartyId>TestParty</nms:PartyId>
<nms:Address/>
</nms:SoldTo>
<nms:BillTo>
<nms:PartyId>TestParty</nms:PartyId>
<nms:Address/>
</nms:BillTo>
<nms:BuyerOrderId>TstBuyer</nms:BuyerOrderId>
<nms:Supplier>
<nms:PartyId>TestParty</nms:PartyId>
<nms:Address/>
</nms:Supplier>
<nms:TermsCode>TestTerms</nms:TermsCode>
<nms:TranspCode>TestTranps</nms:TranspCode>
<nms:DateOrdered>1967-08-13</nms:DateOrdered>
<nms:Backorder>Y</nms:Backorder>
<nms:PORevisionNumber>0</nms:PORevisionNumber>
<nms:POStatusIndicator>N</nms:POStatusIndicator>
<nms:ASNRequirement>Y</nms:ASNRequirement>
<nms:POFileType>P</nms:POFileType>
<nms:ShipTo>
<nms:PartyId>TestParty</nms:PartyId>
<nms:Address/>
</nms:ShipTo>
</nms:POHeader>
<nms:PODetails>
<nms:Items>
<nms:Item>
<nms:POLineNbr>0</nms:POLineNbr>
<nms:BuyerItemId>TestBuyer</nms:BuyerItemId>
<nms:Qty>0.0</nms:Qty>
<nms:QtyUOM>aaaaa</nms:QtyUOM>
<nms:UCValue>0.0</nms:UCValue>
<nms:UCCurrencyCode>aaa</nms:UCCurrencyCode>
<nms:BarCodeId>aaaaaaaaaaaaaa</nms:BarCodeId>
<nms:BarCodeType>GTIN-13</nms:BarCodeType>
</nms:Item>
</nms:Items>
</nms:PODetails>
</nms:PurchaseOrder>
If you inspect the xml message, you can see that the ID field is missing. We will now run the XSLT processor against this xml instance and the Validating XSLT
Below is the command
msxsl -o PO-Result.xml PO-Test.xml PO-Validating.xsl
And below is the contents of PO-Result.xml
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<schematron-output title=”” schemaVersion=”” phase=”#ALL” xmlns:sch=”http://www.ascc.net/xml/schematron” xmlns:nms=”http://www.nmstech.uk/ecommerce/schemas/v01″>
<ns uri=” http://www.nmstech.uk/ecommerce/schemas/v01 ” prefix=”nms” />
<active-pattern name=”Check Existence”/>
<fired-rule id=”” context=”nms:PurchaseOrder” role=”” />
<failed-assert id=”” test=”nms:Id” role=”” location=”/nms:PurchaseOrder[1]”>
<text>PurchaseOrder Id is missing</text>
</failed-assert>
</schematron-output>
What we have done and achieved so far
1. Defined a schematron rules
2. Defined a Schematron Output schema
3. Executed the XSLT processor and got the results.
If you want to have schematron functionality for another flow, all you have to do is create the step 1, i.e. define schematron rules and that’s it, the rest all are the same.