Looping around elements of a message

by eliasen 5. november 2006 13:04

Hi

A guy on the microsoft.public.biztalk.orchestration newsgroup has asked about looping around elements inside an orchestration, and I thought I'd just write some lines about the issue here, for everybody to see in the future.

The problem is, that he has the following document structure:

<Employees>
<Employee title="mgr">
</Employee>
<Employee title="vp">
</Employee>
<Employee title="ceo">
</Employee>
</Employees>

And he wants to do something with each employee, based on what the title is. As I see it, there are two options:

  1. Loop through the Employee-elements inside the orchestration
  2. Use an envelope to split the incoming Employees-message into several Employee-messages

Suggestion 1

I have proposed the following two schemas:

 for the big message that arrives and  for the individual Employee. Note, that I have promoted "title" as a distinguished field.

I then create an orchestration, that takes an instance of the Employees schema as input, and loop around the employees. The orchestration looks like this:

It receives the incoming message, and then initializes a couple of variables. The first expression shape, named "Initialize Loop variables" contains the following three lines:

empCount = xpath(InputMessage, "count(/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''])");
counter = 1;
counterStr = "1";

Basically, I get the number of employee-elements, and initialize the counter. The stringcounter is used to build xpath expression later, as you will see.

Then, I loop. The loop condition is "counter <= empCount" - so I want to loop as long as there are employees.

Inside the scope, I have declared a message employeeMessage, which is of the type of a single employee.

In the message assignment shape, I do this:

EmployeeMessage = xpath(InputMessage, "/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''][" + counterStr + "]");

It takes the employee from the big incoming message that corresponds to the counter and assigns it to the message that is to be constructed.

In the next expression shape, I just write the content of the distinguished field "title" of the employee to the eventlog.

And in the final expression shape, I increment the counter variables:

counter = counter + 1;
counterStr = System.Convert.ToString(counter);

So by doing this, I am looping over the employees inside the employees-message, and I have access to all the values inside the single employee. I didn't have to have schema number 2, describing a single employee, I could have just used xpath all the way down, or maybe declare an XmlNode variable to hold the employee-element instead. But I like this solution better.

Another option I have now is that I can add a decision shape, and based on the title value, I can call different orchestrations, that will handle a specific employee-type. Or perhaps I could just send the employee message to a direct-bound send port and have other orchestrations subscribe to the employee message type. This would require the title to be a promoted property instead of a distinguished field, though, in order to route on it.

Suggestion 2

I propose using an XML Envelope to split the incoming file into several employee-messages and let the orchestration handle them individually.

To do this, I have created two schemas:

 for the envelope and  for the employee. Note: I have changed the names of the root nodes in both schemas. Naturally, in real life you wouldn't do this. The only reason I did this is to be able to have both my examples deployed at the same time. If I hadn't done it, I would have had multiple schemas deployed with the same combination of target namespace and root node, which we all know is BAD. On the schema for the envelope, I have clicked on the "<Schema>"-node and in the properties windows, I have set "Envelope" to "Yes". Then, I clicked on the "EmployeesEnvelope"-node and in the properties window, I set the "Body XPath" property to point at the "EmployeesEnvelope"-element.

Then, I created an orchestration, that takes an employee as the input - not the employees-type, but the single employee. It looks like this:

So here I have a much smaller, simpler, and faster orchestration than the one from suggestion 1.

After the solution is deployed, I create a receive location, and remember to use the default XMLReceive pipeline. The disassembler stage will look at the incoming message, determine the message type, see it is an envelope, split the message into smaller messages, and publish them individually with their own message type.

If I need different orchestrations depending on the value of the title attribute, I can promote it to a promoted property instead of a distinguished field, and add it to a filter on the receive shape in each orchestration.

Examples:

I have my two samples here: LoopAroundEmployee.zip (68,66 KB) and here: LoopAroundEmployeeEnvelope.zip (48,64 KB)

I hope this has been useful for someone. If you have any questions, just ask.

--

eliasen

Tags:

BizTalk 2004 | BizTalk 2006

Comments (13) -

John
John
25-04-2007 13:42:30 #

Thanks! This example was very helpful.

Reply

Jan Eliasen
Jan Eliasen
26-04-2007 09:10:37 #

Anytime!

Reply

Jonas
22-08-2007 09:21:05 #

<b>Thanks!</b> was looking for a way to loop around the order lines of a web order and create a new message from each - this looks like the way to do it Smile just about to try it out now...

Reply

KVK
KVK
19-09-2007 14:36:41 #

Just wondering if this works when EmployeeFromEnvelope is a flat file schema. i am about to try it now...

Reply

Jan Eliasen
Jan Eliasen
19-09-2007 19:04:09 #

Hi

Sure it does. Inside an orchestration, everything is XML, so it will work in exactly the same way.

You can't use an envelope for flat file. For flat file it is called a header schema, body schema and trailer schema. Other than that, they can also be used to split up a flat file into several XML documents.

--
eliasen

Reply

enigel
enigel
27-09-2007 13:08:02 #

Thank you so much! I've just discovered your blog, and your posts are the pillow between my head and the desk as I struggle to learn BizTalk... ;)

Reply

Jan Eliasen
Jan Eliasen
27-09-2007 17:40:28 #

Hi

Thanks for the kind words. It is always nice to have ones work appreciated Smile

--
eliasen

Reply

Hi,
Please i'm trying to apply your loop logic, but i get some xpath error like that :

Event Type:  Error
Event Source:  XLANG/s
Event Category:  None
Event ID:  10034
Date:    26/02/2009
Time:    12:22:44
User:    N/A
Computer:  ALPHA-BIZTALK
Description:
Uncaught exception (see the 'inner exception' below) has suspended an instance of service 'DepotDemandes.Depot(ed088454-7dbd-2295-4855-1dd347aba1ac)'.
The service instance will remain suspended until administratively resumed or terminated.
If resumed the instance will continue from its last persisted state and may re-throw the same unexpected exception.
InstanceId: bbbe8a42-516f-451f-a576-6ff5fd502f17
Shape name: Initialize Loop variables
ShapeId: f7e9649a-dfb8-40b7-b23c-74a4caa512f0
Exception thrown from: segment 1, progress 10
Inner exception: 'count(/*[local-name()='Demandes']/*[local-name()='Demande']' has an invalid token.
        
Exception type: XPathException
Source: System.Xml
Target Site: MS.Internal.Xml.XPath.AstNode ParseMethod(MS.Internal.Xml.XPath.AstNode)
The following is a stack trace that identifies the location where the exception occured

   at MS.Internal.Xml.XPath.XPathParser.ParseMethod(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParsePrimaryExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseFilterExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParsePathExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseUnionExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseUnaryExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseMultiplicativeExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseAdditiveExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseRelationalExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseEqualityExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseAndExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseOrExpr(AstNode qyInput)
   at MS.Internal.Xml.XPath.XPathParser.ParseXPathExpresion(String xpathExpresion)
   at System.Xml.XPath.XPathExpression.Compile(String xpath, IXmlNamespaceResolver nsResolver)
   at System.Xml.XPath.XPathNavigator.Evaluate(String xpath)
   at Microsoft.XLANGs.Core.Part.XPathLoad(Part sourcePart, String xpath, Type dstType)
   at DepotDemandes.Depot.segment1(StopConditions stopOn)
   at Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception& exp)

        
can you help me plz !

Reply

Jan Eliasen
Jan Eliasen
26-02-2009 19:16:04 #

Hi

Well, right now, the only thing I can ses is that the string "count(/*[local-name()='Demandes']/*[local-name()='Demande']" should be "count(/*[local-name()='Demandes']/*[local-name()='Demande'])" instead. Try that. If that fails, try sending me your schema and orchestration.

--
eliasen

Reply

Salam
Salam
07-01-2010 11:59:10 #

very interesting post. I downloaded both and they worklike a charm. However, I have one question regarding 2nd suggestion. How Biztalk messaging engine recognizes that it should use the enveloppe schema? there is no apparent link between both schemas, in orchestration, receive shape is receving a message of type Employee where in the physical port we are submitting an instance of type EmployeesEnvelope.
During my work with BTS, I always had messages suspended if they don't correspond to schema expected by the receive shape, so how this receive shape is accepting a different schema?
thanks in advance

Reply

Jan Eliasen
Jan Eliasen
07-01-2010 17:59:49 #

Hi Salam

When creating a schema, there is a property for the schema called "Envelope". If this property is set to "true", the XML disassembler will automatically treat the incoming message as an envelope message, extracting the inner documents as specified in the "Body XPath" property in the envelope schema. The disassembler will extract the inner documents and submit them on at the time.

Hope this helps?

Reply

Salam
Salam
07-01-2010 19:19:13 #

Understood, this what I have seen. My question is how pipeline becomes aware that he should apply this envelope, no config has been doen except as you said setting a Flag on a schema which is not referenced by the receive shape and the Boday xpath? Do you mean that once we declare an enveloppe schema inside a Biztalk assembly, each xmlreceivepipeline will automatically apply it without the need to do any config? I hope this make it more clear about my query.
regards

Reply

Jan Eliasen
Jan Eliasen
08-01-2010 19:38:29 #

The disassembler looks at the incoming XML and finds the schema that matches the message type of the XML.
If this schema has the "Envelope" property set to true, the disassembler treats the incoming XML as an envelope and starts debatching the XML.

So yes, no confguration necessary. The envelope must just be marked as an envelope and the disassembler does the rest. It will publish each of the messages inside the envelope one at the time with the message type that matches the debatched message promoted, which will then cause the orchestration to pick it up.

Reply

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

Jan Eliasen is 37 years old, divorced and has 2 sons, Andreas (July 2004) and Emil (July 2006).

Jan has a masters degree in computer science and is currently employed at Logica Denmark as an IT architect.

Jan is a 6 times Microsoft MVP in BizTalk Server (not currently an MVP) and proud co-author of the BizTalk 2010 Unleashed book.

BizTalk Server 2010 Unleashed


Buy from Amazon

Microsoft MVP


6 times: July 2004, July 2008, July 2009, July 2010, July 2011, and July 2012. Not currently an MVP.

MCTS

Image to show

Month List

Page List