Dealing with cXML based messages in BizTalk
Thursday, November 29th, 2007cXML (commerce eXtensible Markup Language) is a XML based standard for communication of data related to electronic commerce. The problem from a BizTalk perspective is that they don’t publish any XML schemas (XSD), only Document Type Definition (DTD).
When trying to generate a schema based on a DTD using the functionality in BizTalk (via Add Generated Items) one ends up with a schema split of three files that really doesn’t make any sense (XmlSpy doesn’t do a very good job either …). So after a while I found Nick Heppleston schema repository! After some tweaking I actually had a cXML Order schema in the version I was looking for! Thanks Nick!
The next set of problems was to handle the lack of XML namespace and the DOCTYPE declaration that messages validating against DTD carries on top.
<?xml version="1.0" standalone="no"?> <!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.014/cXML.dtd"> <cXML xml:lang="en-US" payloadID="2007117.25919@Contempus" timestamp="2007-11-07T11:06:16+01:00">
To handel these two issues I set up a receive pipeline that looked like the one below.
Remove the DOCTYPE declaration
First I created a pipeline component to remove the DOCTYPE node. It’s simple code using regular expression to find the DOCTYPE node, replace it with an empty string and return the message.
public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg) { string messageString = new StreamReader(inmsg.BodyPart.Data).ReadToEnd(); Regex doctypePattern = new Regex("<!DOCTYPE.+?>"); messageString = doctypePattern.Replace(messageString, string.Empty); MemoryStream memStream = new MemoryStream(); byte[] data = Encoding.UTF8.GetBytes(messageString); memStream.Write(data, 0, data.Length); memStream.Seek(0, SeekOrigin.Begin); inmsg.BodyPart.Data = memStream; return inmsg; }
Set an XML namespace
Secondly I used Richard Seroter’s post on how to change the SetNSForMsg component to add a XML namespace. That’s the second component showing in the decode stage of the pipeline.
Arrow number 3 shows how the SetMsgNS exposes a property that allows us to set the namespace that we can configure per pipeline. In this case I’ve set it to http://schemas.modhul.com/cXML/1.2.014/OrderRequest which is the namespace of the cXML schema I’m currently working agains.
In the end we’ll have a message with the following declaration and root node.
<?xml version="1.0" encoding="utf-16" standalone="no"?> <cXML xml:lang="en-US" payloadID="2007117.25919@Contempus" xmlns="http://schemas.modhul.com/cXML/1.2.014/OrderRequest" timestamp="2007-11-07T11:06:16+01:00">
Now we’re ready to start mapping!
