XML-Nachrichten nach Knotentyp in Jitterbit Studio weiterleiten
Einführung
Wenn ein einzelner Endpunkt mehr als eine Art von XML-Nachricht liefert, muss die Integration die Nutzlast inspizieren, bevor sie verarbeitet werden kann. Ein gemeinsamer Eingangsordner, eine Warteschlange oder ein API-Endpunkt können sowohl eine Datensatzaktualisierung als auch eine Datensatzstornierung enthalten, die jeweils ein anderes Element unter derselben Wurzel verwenden. Der Vorgang, der Aktualisierungen verarbeitet, kann keine Stornierungsnachricht verarbeiten, daher muss die Nutzlast untersucht und an den Vorgang weitergeleitet werden, der dazu passt.
Um zu testen, ob ein bestimmter Knoten vorhanden ist, führe eine XPath-Abfrage gegen die Nutzlast mit SelectNodes aus und zähle die Ergebnisse mit Length. Ein leeres Ergebnis bedeutet, dass der Knoten nicht vorhanden ist. Dann verzweigst du dich basierend auf diesem Ergebnis und rufst den passenden Vorgang mit RunOperation auf.
Diese Anleitung verwendet eine Bestellnachricht als Beispiel. Beide Nachrichtentypen teilen sich die gleichen Wurzel- und Body-Elemente und unterscheiden sich nur im Element direkt unter dem Body:
Create or update message Cancellation message
Envelope Envelope
└── Body └── Body
└── OrderUpdate └── OrderCancellation
└── Order └── Order
Diese Struktur ist in Interchange-ähnlichen Umschlägen üblich, bei denen ein gemeinsames Wurzelelement entweder einen Datensatz oder ein Ereignis zu diesem Datensatz enthält. Das Ziel besteht darin, zu erkennen, welches von OrderUpdate oder OrderCancellation vorhanden ist, und dann entweder den Vorgang Insert or Update Order oder den Vorgang Cancel Order aufzurufen.
Hinweis
GetNodeName ist dafür ausgelegt, den Namen eines Knotens zu lesen, der bereits von einer Funktion wie SelectSingleNode zurückgegeben wurde, nicht um die Präsenz eines Knotens direkt zu testen. Um es zum Weiterleiten zu verwenden, kombiniere es mit SelectSingleNode wie in Option B unten gezeigt.
Designmuster
Die Weiterleitungslogik befindet sich in einem Skriptschritt in seinem eigenen Router-Vorgang, upstream der Vorgänge, die die Arbeit erledigen:
reads XML] --> B[Script step
router] B --> C[Insert or
Update Order] B --> D[Cancel Order]
Der Router-Vorgang liest die Nutzlast, bestimmt den Nachrichtentyp und ruft genau einen nachgelagerten Vorgang auf. Jeder nachgelagerte Vorgang bleibt einfach, da er nur den Nachrichtentyp erhält, für den er entwickelt wurde.
Schritt 1: Die Nutzlast in eine Variable einlesen
Das Router-Skript benötigt das rohe XML als Zeichenkette. Wie man es erhält, hängt davon ab, wie die Nachricht ankommt.
-
Aus einer Datei- oder Speicheraktivität: Verwende
ReadFilemit einem Referenzpfad zur Leseaktivität:$gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>"); -
Aus einer API Manager API: Verwende die Variable
jitterbit.api.request.body, die die eingereichte Nutzlast enthält:$gv_payload = $jitterbit.api.request.body;
Das Zuweisen der Nutzlast zu einer globalen Variable dient einem zweiten Zweck. Vorgänge, die mit RunOperation aufgerufen werden, erben alle globalen Variablen, sodass der nachgelagerte Vorgang die Nachricht aus $gv_payload lesen kann, ohne die Quelle ein zweites Mal zu lesen.
Schritt 2: Den Namespace identifizieren
Die meisten XML-Daten von Geschäftsanwendungen sind mit Namespaces versehen. Wenn das Wurzelelement der Nutzlast ein xmlns-Attribut trägt, gehört jedes Element im Dokument zu diesem Namespace, und eine XPath-Abfrage, die ihn auslässt, findet nichts.
Öffne eine Beispiel-Nutzlast und schaue dir das Wurzelelement an:
<Envelope xmlns="http://example.com/schemas/orders">
Kopiere den Namespace-URI. Im nächsten Schritt deklarierst du ein Präfix dafür und verwendest dieses Präfix bei jedem Element in der XPath-Abfrage. SelectNodes akzeptiert diese Deklarationen als zusätzliche Zeichenkettenargumente in der Form prefix=uri.
Wenn das Wurzelelement kein xmlns-Attribut hat, ist das Dokument nicht mit Namespaces versehen. Lasse die Präfix-Deklarationen und die Präfixe bei den Elementnamen weg.
Schritt 3: Testen, ob der Knoten vorhanden ist
SelectNodes gibt ein Array aller Knoten zurück, die die Abfrage erfüllt. Wenn nichts übereinstimmt, ist das Array leer, sodass Length den Wert 0 zurückgibt. Der Vergleich dieser Anzahl mit null ist der Existenztest:
$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;
Ersetzen Sie den Namespace-URI durch den aus Schritt 2 und ersetzen Sie die Elementnamen durch die in Ihrer eigenen Payload.
Tipp
Fragen Sie nach dem spezifischen Pfad statt nur nach dem Elementnamen. Ein Pfad, der an der Wurzel verankert ist, bestätigt sowohl, dass das Element vorhanden ist, als auch dass es dort erscheint, wo das Schema es erwartet, was eine falsche Übereinstimmung mit einem gleichnamigen Element an anderer Stelle im Dokument vermeidet.
Schritt 4: Zur entsprechenden Operation weiterleiten
Wählen Sie einen der folgenden zwei Ansätze. Option A ist die direktere Wahl für zwei Nachrichtentypen. Option B eignet sich besser für drei oder mehr, da sie eine XPath-Abfrage ausführt, unabhängig davon, wie viele Nachrichtentypen der Endpunkt trägt.
Option A: Jeden Nachrichtentyp nacheinander testen
Fügen Sie einen Skriptschritt zur Router-Operation hinzu. Das Skript testet zuerst die Update-Nachricht und fällt auf die Stornierungsnachricht zurück.
Ersetzen Sie den Aktivitätsreferenzpfad, den Namespace-URI, die Elementnamen und die zwei Operationsreferenzpfade durch die Werte aus Ihrem eigenen Projekt.
// 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: Den Nachrichtentyp aus dem Text lesen
Da beide Nachrichtentypen an derselben Position im Dokument stehen, können Sie ein beliebiges Element unter dem Text auswählen und seinen Namen lesen, dann auf diesen einzelnen Wert verzweigen. SelectSingleNode gibt den ersten übereinstimmenden Knoten zurück, und GetNodeName gibt seinen Namen zurück. Das * in der XPath-Abfrage erfüllt ein Element mit beliebigem Namen, sodass die Abfrage die Nachrichtentypen nicht im Voraus kennen muss.
Dieser Ansatz erfasst auch den Nachrichtentyp bei jedem Durchlauf im Operationsprotokoll, was nützlich ist, wenn die Payloads des Endpunkts nicht vollständig dokumentiert sind.
// 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)
);
);
Eine Payload, deren Body-Element keinem der Zweige entspricht, fällt durch zum finalen RaiseError, das auch den Fall abdeckt, in dem der Body überhaupt kein untergeordnetes Element hat.
Wichtige Punkte zu beiden Skripten:
RunOperationgibtfalsezurück, wenn die aufgerufene Operation fehlschlägt. Das Testen dieses Rückgabewerts und das Aufrufen vonRaiseErrormitGetLastErrorstoppt die Router-Operation und löst ihre konfigurierte On Fail-Aktion aus. Ohne diesen Test meldet die Router-Operation bei einem Fehler in der nachgelagerten Operation Erfolg.- Das Auslösen eines Fehlers bei einem unbekannten Nachrichtentyp macht Schemaänderungen und fehlerhafte Payloads in den Operationsprotokollen sichtbar, statt die Nachricht unverarbeitet durchzulassen.
RunOperationwird standardmäßig synchron ausgeführt, sodass der Router auf den Abschluss der nachgelagerten Operation wartet. Dies ermöglicht es dem Router, einen Fehler in der nachgelagerten Operation zu erkennen. Eine asynchrone Ausführung würde die Kontrolle sofort zurückgeben und nur melden, ob die Operation in die Warteschlange eingereiht wurde.- Operationen, die mit
RunOperationaufgerufen werden, sind verkettet und werden auf demselben Agent wie der Router ausgeführt. WriteToOperationLogerfasst, welcher Zweig genommen wurde, was eine falsch geleitete Nachricht danach einfach zu diagnostizieren macht.
Schritt 5: Den nachgelagerten Operationen ihre Eingabe geben
Jede nachgelagerte Operation benötigt die Payload, die der Router inspiziert hat. Verwenden Sie je nachdem, was zum Projekt passt:
- Aus der globalen Variablen lesen. Die nachgelagerte Operation erbt
$gv_payloadvom Router. Ordnen Sie oder schreiben Sie direkt aus dieser Variablen, ohne einen zweiten Lesevorgang der Quelle. - Die Quelle erneut lesen. Wenn die Payload in temporärem Speicher oder an einem anderen persistenten Ort sitzt, kann die nachgelagerte Operation ihre eigene Leseaktivität gegen denselben Ort verwenden.
Jede nachgelagerte Operation hat ein Quellschema für nur einen Nachrichtentyp, was ihre Transformation unkompliziert hält.
Integration überprüfen
-
Bereiten Sie eine Beispiel-Payload für jeden Nachrichtentyp vor, plus eine dritte Payload, deren Body-Element keinem entspricht.
-
Stellen Sie die Router-Operation bereit und führen Sie sie aus gegen die Create- oder Update-Nachricht.
-
Bestätigen Sie in den Operationsprotokollen, dass der Router den Update-Pfad protokolliert hat und dass die Operation
Insert or Update Orderausgeführt wurde. Bestätigen Sie, dass die OperationCancel Ordernicht ausgeführt wurde. -
Führen Sie den Router gegen die Stornierungsnachricht aus und bestätigen Sie das Gegenteil: Die Operation
Cancel Orderwurde ausgeführt und die OperationInsert or Update Ordernicht. -
Führen Sie den Router gegen die unbekannte Payload aus und bestätigen Sie, dass die Operation mit dem Fehler „Unrecognized message type" fehlgeschlagen ist und dass keine nachgelagerte Operation ausgeführt wurde.
-
Wenn jede Payload zum unbekannten Branch durchfällt, ist der Namespace das Erste, das überprüft werden sollte. Bestätigen Sie, dass der URI im Skript genau mit dem
xmlns-Wert des Root-Elements der Payload übereinstimmt, einschließlich aller nachfolgenden Schrägstriche, und dass jedes Element in der XPath-Abfrage das deklarierte Präfix trägt. -
Wenn eine Payload zur falschen Operation weitergeleitet wird, protokollieren Sie die Knotenzählungen (Option A) oder den Nachrichtentyp (Option B) und vergleichen Sie sie mit der Beispiel-Payload.
WriteToOperationLog("Update nodes: " + Length($gv_updateNodes))bestätigt, was die Abfrage tatsächlich gefunden hat.
Verwandte Anleitungen
- Operationen verketten und steuern: Verknüpfung von Operationen mit dem Tool „Invoke Operation" oder
RunOperation, einschließlich Fehlererfassung. - Workflows mit Controller-Skripten verwalten: Das umfassendere Controller-Skript-Muster, von dem dieser Router eine Form ist.
- Fehlerbehandlung in Operationen konfigurieren: Festlegung der On Fail-Aktionen, die die
RaiseError-Aufrufe des Routers auslösen. - Datensätze mithilfe von Bedingungen filtern: Verzweigung innerhalb einer Transformation statt zwischen Operationen.