Saltar al contenido

Enrutar mensajes XML por tipo de nodo en Jitterbit Studio

Introducción

Cuando un único endpoint entrega más de un tipo de mensaje XML, la integración debe inspeccionar la carga útil antes de procesarla. Una carpeta compartida de entrada, una cola o un endpoint de API pueden transportar tanto una actualización de registro como una cancelación de registro, cada una usando un elemento diferente bajo la misma raíz. La operación que maneja actualizaciones no puede procesar un mensaje de cancelación, así que hay que examinar la carga útil y enrutarla a la operación que le corresponde.

Para verificar si un nodo específico está presente, ejecuta una consulta XPath contra la carga útil con SelectNodes y cuenta los resultados con Length. Un resultado vacío significa que el nodo está ausente. Luego se ramifica en ese resultado y se llama a la operación que coincide con RunOperation.

Esta guía usa un mensaje de orden como ejemplo. Ambos tipos de mensaje comparten los mismos elementos raíz y cuerpo, y difieren solo en el elemento directamente debajo del cuerpo:

Create or update message        Cancellation message

Envelope                        Envelope
└── Body                        └── Body
    └── OrderUpdate                 └── OrderCancellation
        └── Order                       └── Order

Esta estructura es común en sobres de estilo intercambio, donde un elemento raíz compartido transporta ya sea un registro o un evento sobre ese registro. El objetivo es detectar cuál de OrderUpdate u OrderCancellation está presente, e invocar ya sea la operación Insert or Update Order o la operación Cancel Order.

Nota

GetNodeName está diseñado para leer el nombre de un nodo ya devuelto por una función como SelectSingleNode, no para verificar la presencia de un nodo directamente. Para usarlo en enrutamiento, combínalo con SelectSingleNode como se muestra en la Opción B abajo.

Patrón de diseño

La lógica de enrutamiento vive en un paso de script en su propia operación enrutadora, aguas arriba de las operaciones que hacen el trabajo:

%%{init: {"themeVariables": {"lineColor": "#6b7280", "edgeLabelBackground": "#f5f5f5"}}}%% flowchart LR A[Source activity
reads XML] --> B[Script step
router] B --> C[Insert or
Update Order] B --> D[Cancel Order]

La operación enrutadora lee la carga útil, determina el tipo de mensaje e invoca exactamente una operación aguas abajo. Cada operación aguas abajo se mantiene simple, porque solo recibe el tipo de mensaje para el que fue construida.

Paso 1: Lee la carga útil en una variable

El script enrutador necesita el XML sin procesar como una cadena. Cómo lo obtienes depende de cómo llegue el mensaje.

  • De una actividad de archivo o almacenamiento: Usa ReadFile con una ruta de referencia a la actividad de lectura:

    $gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>");
    
  • De una API de API Manager: Usa la variable jitterbit.api.request.body, que contiene la carga útil enviada:

    $gv_payload = $jitterbit.api.request.body;
    

Asignar la carga útil a una variable global sirve un segundo propósito. Las operaciones llamadas con RunOperation heredan todas las variables globales, así que la operación aguas abajo puede leer el mensaje de $gv_payload sin leer la fuente una segunda vez.

Paso 2: Identifica el espacio de nombres

La mayoría del XML de aplicaciones empresariales tiene un espacio de nombres. Si el elemento raíz de la carga útil tiene un atributo xmlns, cada elemento en el documento pertenece a ese espacio de nombres, y una consulta XPath que lo omite no coincide con nada.

Abre una carga útil de ejemplo y mira el elemento raíz:

<Envelope xmlns="http://example.com/schemas/orders">

Copia el URI del espacio de nombres. En el siguiente paso, declaras un prefijo para él y usas ese prefijo en cada elemento de la consulta XPath. SelectNodes acepta estas declaraciones como argumentos de cadena adicionales en forma prefix=uri.

Si el elemento raíz no tiene un atributo xmlns, el documento no tiene espacio de nombres. Omite las declaraciones de prefijo y los prefijos en los nombres de elementos.

Paso 3: Verificar si el nodo existe

SelectNodes devuelve un array con todos los nodos que coinciden con la consulta. Cuando no hay coincidencias, el array está vacío, por lo que Length devuelve 0. Comparar ese conteo con cero es la prueba de existencia:

$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;

Reemplaza el URI del espacio de nombres con el del Paso 2, y reemplaza los nombres de los elementos con los de tu propia carga.

Consejo

Consulta la ruta específica en lugar del nombre del elemento solamente. Una ruta anclada en la raíz confirma tanto que el elemento está presente como que aparece donde el esquema lo espera, lo que evita una coincidencia falsa en un elemento con el mismo nombre en otra parte del documento.

Paso 4: Enrutar a la operación coincidente

Elige uno de los dos enfoques siguientes. La Opción A es la opción más directa para dos tipos de mensajes. La Opción B es la más adecuada para tres o más, porque ejecuta una consulta XPath independientemente de cuántos tipos de mensajes lleve el endpoint.

Opción A: Verificar cada tipo de mensaje por turno

Añade un paso de script a la operación del enrutador. El script verifica primero el mensaje de actualización y regresa al mensaje de cancelación.

Reemplaza la ruta de referencia de la actividad, el URI del espacio de nombres, los nombres de los elementos y las dos rutas de referencia de operación con los valores de tu propio proyecto.

// 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.")
    );
);

Opción B: Leer el tipo de mensaje del cuerpo

Dado que ambos tipos de mensajes ocupan la misma posición en el documento, puedes seleccionar cualquier elemento que esté bajo el cuerpo y leer su nombre, luego ramificarte en ese valor único. SelectSingleNode devuelve el primer nodo coincidente, y GetNodeName devuelve su nombre. El * en la consulta XPath coincide con un elemento de cualquier nombre, por lo que la consulta no necesita conocer los tipos de mensajes de antemano.

Este enfoque también registra el tipo de mensaje en el registro de operación en cada ejecución, lo que es útil cuando las cargas del endpoint no están completamente documentadas.

// 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)
    );
);

Una carga cuyo elemento body no coincide con ninguna de las ramas pasa a través del RaiseError final, que también cubre el caso en el que el body no tiene ningún elemento hijo en absoluto.

Puntos clave acerca de ambos scripts:

  • RunOperation devuelve false cuando la operación llamada falla. Verificar ese valor de retorno y llamar a RaiseError con GetLastError detiene la operación del enrutador y activa su acción On Fail configurada. Sin esta verificación, una falla en la operación descendente deja el enrutador reportando éxito.
  • Generar un error en un tipo de mensaje no reconocido expone los cambios de esquema y las cargas malformadas en los registros de operación en lugar de permitir que el mensaje pase sin procesar.
  • RunOperation se ejecuta de manera síncrona por defecto, por lo que el enrutador espera a que la operación descendente finalice. Esto es lo que permite al enrutador detectar una falla descendente. La ejecución asíncrona devolvería el control inmediatamente y reportaría solo si la operación fue puesta en cola.
  • Las operaciones llamadas con RunOperation están encadenadas y se ejecutan en el mismo agente que el enrutador.
  • WriteToOperationLog registra qué rama se tomó, lo que hace que un mensaje enrutado incorrectamente sea sencillo de diagnosticar después de los hechos.

Paso 5: Proporcionar entrada a las operaciones descendentes

Cada operación descendente necesita la carga que el enrutador inspeccionó. Usa la que se ajuste al proyecto:

  • Leer desde la variable global. La operación descendente hereda $gv_payload del enrutador. Asigna o crea un script a partir de esa variable directamente, sin una segunda lectura de la fuente.
  • Leer la fuente nuevamente. Si la carga está en almacenamiento temporal u otra ubicación persistente, la operación descendente puede usar su propia actividad de lectura contra la misma ubicación.

Cada operación descendente tiene un esquema de origen para un solo tipo de mensaje, lo que mantiene su transformación directa.

Verificar la integración

  1. Prepara una muestra de carga útil de cada tipo de mensaje, más una tercera carga cuyo elemento body no coincida con ninguna.

  2. Implementa y ejecuta la operación de enrutador contra el mensaje de creación o actualización.

  3. En los registros de operación, confirma que el enrutador registró la ruta de actualización y que se ejecutó la operación Insert or Update Order. Confirma que la operación Cancel Order no se ejecutó.

  4. Ejecuta el enrutador contra el mensaje de cancelación y confirma lo opuesto: se ejecutó la operación Cancel Order y la operación Insert or Update Order no se ejecutó.

  5. Ejecuta el enrutador contra la carga no reconocida y confirma que la operación falló con el error "Unrecognized message type" y que ninguna operación descendente se ejecutó.

  6. Si toda carga cae en la rama no reconocida, el espacio de nombres es lo primero que debes revisar. Confirma que el URI en el script coincida exactamente con el valor xmlns del elemento raíz de la carga, incluyendo cualquier barra diagonal final, y que cada elemento en la consulta XPath lleve el prefijo declarado.

  7. Si una carga se enruta a la operación incorrecta, registra los recuentos de nodos (Opción A) o el tipo de mensaje (Opción B) y compáralos con la carga de muestra. WriteToOperationLog("Update nodes: " + Length($gv_updateNodes)) confirma lo que la consulta realmente coincidió.