I can’t remember how many times I have read entries posted on the various forums asking how to get looping correct in the HL7 messages. A couple of friends have asked how I have done it, so I thought that I would post how you do it.
The real issue is that the looping does not follow the necessary structure defined in the HL7 schemas. The source records in many cases need to match with sequence group (which is not possible in the BizTalk mapper). In the following example, after mapping out some sample data, I manually ran the map, and this is the result I received for the ORU_R01:

but this will not work, because OBR 4.1 does not repeat and will cause the BTAHL7 ASM will throw errors, for this and a LOT of other non-conforming message structures.
In the mapper, what I really need is highlighted in RED:

So I reverted to XSLT to do what I needed to be done. I did all of the mapping, afterwards, I right clicked the map and chose Validate Map, and opened up the TestMap_xslt.xml in a text editor.
I then edited the xslt and moved around/deleted the xsl:for-each select=”Order” tags, and also some of the tags. I then saved the document as XSLTMap.xslt.I created a new map (XSLTMap.btm), defined the input schema and the output schema, clicked on the grid and chose Custom XSLT Path and browsed to the xslt file I just created (XSLTMap.xslt). I then tested it against the xml document and made sure that it looked correct.
In the orchestration I created a construct shape, and created 3 maps that defined all three message parts (compared to how the tutorial works, as I don’t really like to hard code stuff in a message assignment shape). I did have to assign some context properties in a message assignment shape, and then sent it off.
I ended up getting the following error:
Alternate Error Number: 301
Alternate Error Description: XmlReader not positioned at root elment of ‘ORU_R01_231_GLO_DEF’
Alternate Encoding System: HL7-BTA
The issue ended up being that in my custom xslt, there is the following tag: omit-xml-declaration=”no”
This caused the BodySegments message part to look like this at the beginning of the message:

So in the xslt, it is necessary to make sure that the omit-xml-declaration=”yes”
Here is the example (BizTalk 2004) that transforms the following XML message:

And transforms it in the correct repeating structure to:
MSH|^~\&|Sender||Receiver||||ORU^R01|1234567|D|2.3.1
OBR||||^ServiceID_1
NTE|||Note_1
OBX||AD|^Text_1||||||||C
NTE|||Comment_1~Comment_2
OBX||CE|^Text_2||||||||D
NTE|||Comment_3~Comment_4
OBX||CF|^Text_3||||||||F
NTE|||Comment_5~Comment_6
OBX||CK|^Text_4||||||||I
NTE|||Comment_7
CTI|^^Id_1
OBR||||^ServiceID_2
NTE|||Note_2
OBX||CN|^Text_5||||||||N
NTE|||Comment_8~Comment_9
OBX||CP|^Text_6||||||||O
NTE|||Comment_10
CTI|^^Id_2
So in order to keep the correct looping, you need to be a little XSLT savy, but after playing with it for a little bit, you should be able to get your output correct.
The solution has the initial mapping called TestMap.btm, the results of that map:HL7Msg_MisAlligned_BodySegments.xml, the final map: XSLTMap.btm, the trigger xml:Data.xml, along with the 2XCommon and 231Common projects.
I checked with some friends at Microsoft to confirm that this is the only solution for the looping dilemma but it looks like there is light at the end of the tunnel (I will post the official documentation as soon as I know):
“This is a known issue in the BizTalk mapper which impacts mapping HL7 v2.x schemas.
I’m happy to report some good news on this. A DCR, to allow the BizTalk mapper to preserve order for repeating segments in the XSLT generation process, has been accepted this week to be included in BizTalk Server 2006 R2. In the meantime, we are documenting a process that requires generating an XSLT with the BizTalk mapper, then manually inserting a loop in the XSLT around the nodes in the sequence where the order needs to be preserved. “