Route XML messages by node type in Jitterbit Studio
Introduction
When a single endpoint delivers more than one kind of XML message, the integration must inspect the payload before it can process it. A shared inbound folder, queue, or API endpoint may carry both a record update and a record cancellation, each using a different element under the same root. The operation that handles updates cannot process a cancellation message, so the payload has to be examined and routed to the operation that matches it.
To test whether a specific node is present, run an XPath query against the payload with SelectNodes and count the results with Length. An empty result means the node is absent. You then branch on that result and call the matching operation with RunOperation.
This guide uses an order message as the example. Both message types share the same root and body elements, and differ only in the element directly beneath the body:
Create or update message Cancellation message
Envelope Envelope
└── Body └── Body
└── OrderUpdate └── OrderCancellation
└── Order └── Order
This shape is common in interchange-style envelopes, where a shared root element carries either a record or an event about that record. The goal is to detect which of OrderUpdate or OrderCancellation is present, then invoke either the Insert or Update Order operation or the Cancel Order operation.
Note
GetNodeName is designed to read the name of a node already returned by a function such as SelectSingleNode, not to test for a node's presence directly. To use it for routing, pair it with SelectSingleNode as shown in Option B below.
Design pattern
The routing logic lives in a script step in its own router operation, upstream of the operations that do the work:
reads XML] --> B[Script step
router] B --> C[Insert or
Update Order] B --> D[Cancel Order]
The router operation reads the payload, determines the message type, and calls exactly one downstream operation. Each downstream operation stays simple, because it only ever receives the message type it was built for.
Step 1: Read the payload into a variable
The router script needs the raw XML as a string. How you obtain it depends on how the message arrives.
-
From a file or storage activity: Use
ReadFilewith a reference path to the read activity:$gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>"); -
From an API Manager API: Use the
jitterbit.api.request.bodyvariable, which holds the submitted payload:$gv_payload = $jitterbit.api.request.body;
Assigning the payload to a global variable serves a second purpose. Operations called with RunOperation inherit all global variables, so the downstream operation can read the message from $gv_payload without reading the source a second time.
Step 2: Identify the namespace
Most XML from business applications is namespaced. If the payload's root element carries an xmlns attribute, every element in the document belongs to that namespace, and an XPath query that omits it matches nothing.
Open a sample payload and look at the root element:
<Envelope xmlns="http://example.com/schemas/orders">
Copy the namespace URI. In the next step, you declare a prefix for it and use that prefix on each element in the XPath query. SelectNodes accepts these declarations as additional string arguments in prefix=uri form.
If the root element has no xmlns attribute, the document is not namespaced. Omit the prefix declarations and the prefixes on the element names.
Step 3: Test whether the node exists
SelectNodes returns an array of every node the query matches. When nothing matches, the array is empty, so Length returns 0. Comparing that count to zero is the existence test:
$gv_updateNodes = SelectNodes($gv_payload,
"/o:Envelope/o:Body/o:OrderUpdate",
"o=http://example.com/schemas/orders");
// True when the payload contains a create or update message
Length($gv_updateNodes) > 0;
Replace the namespace URI with the one from Step 2, and replace the element names with those in your own payload.
Tip
Query for the specific path rather than the element name alone. A path anchored at the root confirms both that the element is present and that it appears where the schema expects it, which avoids a false match on a same-named element elsewhere in the document.
Step 4: Route to the matching operation
Choose one of the following two approaches. Option A is the more direct choice for two message types. Option B is the better fit for three or more, because it runs one XPath query regardless of how many message types the endpoint carries.
Option A: Test each message type in turn
Add a script step to the router operation. The script tests for the update message first and falls back to the cancellation message.
Replace the activity reference path, the namespace URI, the element names, and the two operation reference paths with the values from your own project.
// Read the inbound message
$gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>");
// Look for the create or update message: Envelope/Body/OrderUpdate
$gv_updateNodes = SelectNodes($gv_payload,
"/o:Envelope/o:Body/o:OrderUpdate",
"o=http://example.com/schemas/orders");
// Look for the cancellation message: Envelope/Body/OrderCancellation
$gv_cancelNodes = SelectNodes($gv_payload,
"/o:Envelope/o:Body/o:OrderCancellation",
"o=http://example.com/schemas/orders");
If(Length($gv_updateNodes) > 0,
WriteToOperationLog("Routing to insert or update.");
If(!RunOperation("<TAG>operation:Insert or Update Order</TAG>"),
RaiseError(GetLastError())
);
,
If(Length($gv_cancelNodes) > 0,
WriteToOperationLog("Routing to cancellation.");
If(!RunOperation("<TAG>operation:Cancel Order</TAG>"),
RaiseError(GetLastError())
);
,
RaiseError("Unrecognized message type: no OrderUpdate or OrderCancellation node found.")
);
);
Option B: Read the message type from the body
Because both message types occupy the same position in the document, you can select whatever element sits under the body and read its name, then branch on that single value. SelectSingleNode returns the first matching node, and GetNodeName returns its name. The * in the XPath query matches an element of any name, so the query does not need to know the message types in advance.
This approach also records the message type in the operation log on every run, which is useful when the endpoint's payloads are not fully documented.
// Read the inbound message
$gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>");
// Select whatever element sits directly under Body, then read its name
$gv_bodyChild = SelectSingleNode($gv_payload,
"/o:Envelope/o:Body/*",
"o=http://example.com/schemas/orders");
$gv_messageType = GetNodeName($gv_bodyChild);
WriteToOperationLog("Message type: " + $gv_messageType);
// Route on the message type. Add a branch for each additional type,
// and raise an error on anything unrecognized.
If($gv_messageType == "OrderUpdate",
If(!RunOperation("<TAG>operation:Insert or Update Order</TAG>"),
RaiseError(GetLastError())
);
,
If($gv_messageType == "OrderCancellation",
If(!RunOperation("<TAG>operation:Cancel Order</TAG>"),
RaiseError(GetLastError())
);
,
RaiseError("Unrecognized message type: " + $gv_messageType)
);
);
A payload whose body element matches none of the branches falls through to the final RaiseError, which also covers the case where the body has no child element at all.
Key points about both scripts:
RunOperationreturnsfalsewhen the called operation fails. Testing that return value and callingRaiseErrorwithGetLastErrorstops the router operation and triggers its configured On Fail action. Without this test, a failure in the downstream operation leaves the router reporting success.- Raising an error on an unrecognized message type surfaces schema changes and malformed payloads in the operation logs instead of allowing the message to pass through unprocessed.
RunOperationruns synchronously by default, so the router waits for the downstream operation to finish. This is what allows the router to detect a downstream failure. Running asynchronously would return control immediately and report only whether the operation was queued.- Operations called with
RunOperationare chained and run on the same agent as the router. WriteToOperationLogrecords which branch was taken, which is what makes a misrouted message straightforward to diagnose after the fact.
Step 5: Give the downstream operations their input
Each downstream operation needs the payload the router inspected. Use whichever of these fits the project:
- Read from the global variable. The downstream operation inherits
$gv_payloadfrom the router. Map or script from that variable directly, with no second read of the source. - Read the source again. If the payload sits in temporary storage or another persistent location, the downstream operation can use its own read activity against the same location.
Each downstream operation has a source schema for one message type only, which is what keeps its transformation straightforward.
Verify the integration
-
Prepare one sample payload of each message type, plus a third payload whose body element matches neither.
-
Deploy and run the router operation against the create or update message.
-
In the operation logs, confirm that the router logged the update path and that the
Insert or Update Orderoperation ran. Confirm that theCancel Orderoperation did not run. -
Run the router against the cancellation message and confirm the opposite: the
Cancel Orderoperation ran and theInsert or Update Orderoperation did not. -
Run the router against the unrecognized payload and confirm that the operation failed with the "Unrecognized message type" error and that neither downstream operation ran.
-
If every payload falls through to the unrecognized branch, the namespace is the first thing to check. Confirm that the URI in the script matches the
xmlnsvalue on the payload's root element exactly, including any trailing slash, and that each element in the XPath query carries the declared prefix. -
If a payload routes to the wrong operation, log the node counts (Option A) or the message type (Option B) and compare them against the sample payload.
WriteToOperationLog("Update nodes: " + Length($gv_updateNodes))confirms what the query actually matched.
Related guides
- Chain and control operations: Linking operations with the Invoke Operation tool or
RunOperation, including error capture. - Manage workflows using controller scripts: The broader controller script pattern this router is one form of.
- Configure error handling in operations: Setting the On Fail actions that the router's
RaiseErrorcalls trigger. - Filter records using conditions: Branching within a transformation rather than between operations.