Ir para o conteúdo

Rotear mensagens XML por tipo de nó no Jitterbit Studio

Introdução

Quando um único endpoint entrega mais de um tipo de mensagem XML, a integração deve inspecionar o payload antes de processá-lo. Uma pasta de entrada compartilhada, fila ou endpoint de API pode conter tanto uma atualização de registro quanto um cancelamento de registro, cada um usando um elemento diferente sob a mesma raiz. A operação que trata atualizações não pode processar uma mensagem de cancelamento, portanto o payload deve ser examinado e roteado para a operação que corresponde a ele.

Para testar se um nó específico está presente, execute uma consulta XPath contra o payload com SelectNodes e conte os resultados com Length. Um resultado vazio significa que o nó está ausente. Depois você faz uma ramificação nesse resultado e chama a operação correspondente com RunOperation.

Este guia usa uma mensagem de pedido como exemplo. Ambos os tipos de mensagem compartilham os mesmos elementos raiz e corpo, e diferem apenas no elemento diretamente abaixo do corpo:

Create or update message        Cancellation message

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

Esta forma é comum em envelopes no estilo de intercâmbio, onde um elemento raiz compartilhado carrega um registro ou um evento sobre esse registro. O objetivo é detectar qual de OrderUpdate ou OrderCancellation está presente, e então invocar a operação Insert or Update Order ou a operação Cancel Order.

Nota

GetNodeName foi desenvolvida para ler o nome de um nó já retornado por uma função como SelectSingleNode, não para testar a presença de um nó diretamente. Para usá-la no roteamento, combine-a com SelectSingleNode conforme mostrado em Opção B abaixo.

Padrão de design

A lógica de roteamento fica em uma etapa de script em sua própria operação de roteador, a montante das operações que fazem o trabalho:

%%{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]

A operação de roteador lê o payload, determina o tipo de mensagem e chama exatamente uma operação a jusante. Cada operação a jusante permanece simples, porque recebe apenas o tipo de mensagem para o qual foi construída.

Etapa 1: Ler o payload em uma variável

O script de roteador precisa do XML bruto como uma string. Como você o obtém depende de como a mensagem chega.

  • De uma atividade de arquivo ou armazenamento: Use ReadFile com um caminho de referência para a atividade de leitura:

    $gv_payload = ReadFile("<TAG>activity:tempstorage/Inbound XML/tempstorage_read/Read Message</TAG>");
    
  • De uma API do API Manager: Use a variável jitterbit.api.request.body, que contém o payload enviado:

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

Atribuir o payload a uma variável global serve a um segundo propósito. Operações chamadas com RunOperation herdam todas as variáveis globais, então a operação a jusante pode ler a mensagem de $gv_payload sem ler a fonte uma segunda vez.

Etapa 2: Identificar o namespace

A maioria do XML de aplicações comerciais possui namespace. Se o elemento raiz do payload tiver um atributo xmlns, todos os elementos no documento pertencem a esse namespace, e uma consulta XPath que o omite não encontra nada.

Abra um payload de exemplo e observe o elemento raiz:

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

Copie o URI do namespace. Na próxima etapa, você declara um prefixo para ele e usa esse prefixo em cada elemento na consulta XPath. SelectNodes aceita essas declarações como argumentos de string adicionais na forma prefix=uri.

Se o elemento raiz não tiver um atributo xmlns, o documento não possui namespace. Omita as declarações de prefixo e os prefixos nos nomes dos elementos.

Etapa 3: Testar se o nó existe

SelectNodes retorna uma matriz de cada nó que a consulta encontra. Quando nada corresponde, a matriz está vazia, então Length retorna 0. Comparar essa contagem com zero é o teste de existência:

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

Substitua o URI do namespace por aquele da Etapa 2 e substitua os nomes dos elementos pelos de seu próprio payload.

Dica

Faça consultas para o caminho específico em vez de apenas o nome do elemento. Um caminho ancorado na raiz confirma tanto que o elemento está presente quanto que aparece onde o schema o espera, o que evita uma correspondência falsa em um elemento de mesmo nome em outro lugar do documento.

Etapa 4: Rotear para a operação correspondente

Escolha uma das duas abordagens a seguir. A Opção A é a escolha mais direta para dois tipos de mensagem. A Opção B é mais adequada para três ou mais, pois executa uma consulta XPath independentemente de quantos tipos de mensagem o endpoint transporta.

Opção A: Testar cada tipo de mensagem por vez

Adicione uma etapa de script à operação de roteamento. O script testa a mensagem de atualização primeiro e recua para a mensagem de cancelamento.

Substitua o caminho de referência da atividade, o URI do namespace, os nomes dos elementos e os dois caminhos de referência da operação pelos valores de seu próprio projeto.

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

Opção B: Ler o tipo de mensagem do corpo

Como ambos os tipos de mensagem ocupam a mesma posição no documento, você pode selecionar qualquer elemento que esteja sob o corpo e ler seu nome, depois ramificar nesse único valor. SelectSingleNode retorna o primeiro nó correspondente, e GetNodeName retorna seu nome. O * na consulta XPath corresponde a um elemento de qualquer nome, então a consulta não precisa conhecer os tipos de mensagem com antecedência.

Essa abordagem também registra o tipo de mensagem no log de operações em cada execução, o que é útil quando os payloads do endpoint não estão totalmente documentados.

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

Um payload cujo elemento de corpo não corresponde a nenhuma das ramificações passa para o RaiseError final, que também cobre o caso em que o corpo não tem elemento filho algum.

Pontos-chave sobre ambos os scripts:

  • RunOperation retorna false quando a operação chamada falha. Testar esse valor de retorno e chamar RaiseError com GetLastError interrompe a operação de roteamento e dispara sua ação On Fail configurada. Sem esse teste, uma falha na operação downstream deixa o roteador informando sucesso.
  • Gerar um erro em um tipo de mensagem não reconhecido evidencia alterações de schema e payloads malformados nos logs de operações em vez de permitir que a mensagem passe sem processamento.
  • RunOperation é executado sincronamente por padrão, portanto o roteador aguarda a conclusão da operação downstream. Isso é o que permite ao roteador detectar uma falha downstream. A execução assíncrona devolveria o controle imediatamente e informaria apenas se a operação foi enfileirada.
  • As operações chamadas com RunOperation são encadeadas e executadas no mesmo agent que o roteador.
  • WriteToOperationLog registra qual ramificação foi seguida, o que torna direto diagnosticar uma mensagem roteada incorretamente depois do fato.

Etapa 5: Fornecer entrada às operações downstream

Cada operação downstream precisa do payload que o roteador inspecionou. Use o que se encaixa melhor no projeto:

  • Ler da variável global. A operação downstream herda $gv_payload do roteador. Mapeie ou faça script dessa variável diretamente, sem uma segunda leitura da origem.
  • Ler a origem novamente. Se o payload estiver em armazenamento temporário ou em outro local persistente, a operação downstream pode usar sua própria atividade de leitura contra o mesmo local.

Cada operação downstream tem um esquema de origem para apenas um tipo de mensagem, o que mantém sua transformação simples.

Verificar a integração

  1. Prepare um payload de amostra de cada tipo de mensagem, mais um terceiro payload cujo elemento body não corresponda a nenhum deles.

  2. Implante e execute a operação do roteador contra a mensagem de criação ou atualização.

  3. Nos logs da operação, confirme que o roteador registrou o caminho de atualização e que a operação Insert or Update Order foi executada. Confirme que a operação Cancel Order não foi executada.

  4. Execute o roteador contra a mensagem de cancelamento e confirme o oposto: a operação Cancel Order foi executada e a operação Insert or Update Order não foi.

  5. Execute o roteador contra o payload não reconhecido e confirme que a operação falhou com o erro "Unrecognized message type" e que nenhuma operação downstream foi executada.

  6. Se todo payload cair no branch não reconhecido, o namespace é a primeira coisa a verificar. Confirme que o URI no script corresponde exatamente ao valor xmlns no elemento raiz do payload, incluindo qualquer barra à direita, e que cada elemento na consulta XPath tenha o prefixo declarado.

  7. Se um payload for roteado para a operação errada, registre a contagem de nós (Opção A) ou o tipo de mensagem (Opção B) e compare com o payload de amostra. WriteToOperationLog("Update nodes: " + Length($gv_updateNodes)) confirma o que a consulta realmente correspondeu.