Os mapas, ou transformações, são um dos componentes mais comuns nos processos de integração. Funcionam como tradutores essenciais no desacoplamento entre os diferentes sistemas a interligar. Este artigo tem como objectivo explicar como os mapas são processados internamente pelo motor do produto à medida que exploramos o editor de mapas do BizTalk Server. Este artigo tem como base o exemplo do artigo publicado no artigo BizTalk Server - Princípios básicos dos Mapas (pt-BR) onde é explicado em detalhe as funcionalidades básicas dos mapas e como podem ser implementadas. Pretende ser uma nota introdutória e destinada a quem está a dar os primeiros passos nesta tecnologia. Conforme explicado no artigo anterior, quando estamos a efectuar uma transformação de mensagens são 5 as funcionalidades comuns que normalmente nos surgem:
Tendo por base estas funcionalidades vamos explicar como o motor de mapas do BizTalk traduz e processa estas ligações internamente. Para melhor compreendermos o seu funcionamento efectuamos algumas alterações à estrutura do esquema (schema) do documento final: acrescentamos um elemento opcional (“EstadoCivil”) e desorganizamos intencionalmente a estrutura do documento.
Embora tradicionalmente a informação seja extraída da origem à medida que vai sendo processada, na realidade nos modelos baseado em XSLT o que acontece é exactamente o contrário: Cada elemento no destino provoca a procura pelo correspondente na origem. Vejamos um exemplo tradicional:
O BizTalk também utiliza esta técnica nas conversões dos ficheiros texto (Flat Files) para formato XML (transformações de sintaxe, também explicado no artigo anterior), no entanto as transformações nos mapas utilizam uma abordagem diferente, como iremos verificar mais à frente neste artigo. Um dos factores importantes quando utilizamos ferramentas de integração é também termos em atenção as tecnologias standards existentes, e foi isso o que os criadores do produto fizeram. O BizTalk trabalha internamente, quase exclusivamente, com documentos XML, sendo que fazia sentido utilizarem uma tecnologia standard para efectuarem este tipo de transformações, para isso o W3C definiu o XSLT (Extensible Stylesheet Language Transformation) como o formato padrão para representar as transformações entre documentos XML. Desta forma todas as ligações e functoids que são visíveis graficamente na grelha de mapeamentos não são mais do que uma representação gráfica de um documento XSLT que permite transformar o documento de origem num determinado formato especificado pelo esquema de destino. Podemos dizer que os mapas de BizTalk têm sempre o seu foco no documento final, fazendo assim sentido que as regras de transformação sejam processadas na sequência requerida para o criar. Quando o mapa é compilado, essas regras são traduzidas em queries XPATH e funções XSLT por forma a transformar a informação pretendida, ou seja, as regras de mapeamento são construídas a partir da estrutura de destino e não da origem como algumas ferramentas tradicionais. Sendo assim, os mapas de BizTalk seguem o seguinte modelo:
Nota: Podemos utilizar um XSLT criado por uma aplicação externa e incluí-lo no mapa através de XSLT custom script ou importando um ficheiro XSLT que efectua a transformação total do mapa (obviamente o editor gráfico do mapa de BizTalk não representará as ligações visualmente).
Neste artigo vamos utilizar as operações básicas de mapeamento descritas anteriormente, e analisar as decisões tomadas pelo “compilador” de mapas do BizTalk Mapper Designer. Basicamente neste mapeamento existem dois esquemas similares, no qual pretendemos mapear os elementos da origem no seu correcto destino e ao qual implementamos os seguintes desafios:
Conforme podem verificar, intencionalmente trocamos a ordem dos elementos no esquema de origem, por forma a verificarmos com mais facilidade como os mapas de BizTalk funcionam. Desta forma obtivemos o seguinte mapa final:
<
Morada
>
xsl:value-of
select
=
"Morada/text()"
/>
</
xsl:variable
name
"var:v1"
"userCSharp:LogicalIsString(string(CodigoPostal/text()))"
xsl:if
test
"string($var:v1)='true'"
"var:v2"
"CodigoPostal/text()"
CodigoPostal
"$var:v2"
"var:v3"
"userCSharp:StringConcat(string(Nome/text()) , " " , string(Apelido/text()))"
NomeCompleto
"$var:v3"
"var:v4"
"userCSharp:CalcularIdade(string(DataNascimento/text()))"
Idade
"$var:v4"
Facturacao
"var:v5"
"userCSharp:InitCumulativeSum(0)"
xsl:for-each
"/s0:PessoaOrigem/Chamada"
"var:v6"
"userCSharp:StringLeft(string(@Destino) , "4")"
"var:v7"
"userCSharp:LogicalEq(string($var:v6) , "+351")"
"string($var:v7)='true'"
"var:v8"
"@Custo"
"var:v9"
"userCSharp:AddToCumulativeSum(0,string($var:v8),"1000")"
"var:v10"
"userCSharp:GetCumulativeSum(0)"
TotalInternacional
"$var:v10"
…
“A ordem com que as ligações são associadas no destino tem um grande impacto no resultado final.”… Esta afirmação é verdadeira e ao mesmo tempo falsa! Na realidade a ordem com que associamos as ligações (Drag&Drop) dos elementos de origem para diferentes elementos de destino é irrelevante, uma vez que o compilador, conforme explicado anteriormente, irá processar pela ordem correcta… Excepto se tivermos de associar diversas ligações para o mesmo elemento de destino ou functoid. Nestes dois últimos casos a ordem com que se efectua a associação é extremamente importante, podendo originar resultados inesperados.
Uma grande parte das functoids existentes na Toolbox espera vários parâmetros de entrada, um exemplo prático é a functoid “Value Mapping Functoid”. Esta functoid retorna o valor do segundo parâmetro se o valor do primeiro for igual a “True”, caso contrário não é retornado nada. Desta forma é necessário respeitar a ordem com que associamos as ligações:
A troca na associação das ligações irá originar erros de mapeamento ou em resultados inesperados, conforme a functoid utilizada. Reorganização das ligações (links) nas functoids é muito fácil, para isso basta abrir o detalhe (duplo clique) e usar os botões de ordenação.
Alterar a ordem da sequência na associação das ligações no mesmo elemento do esquema de destino poderá também ter impacto no resultado final pretendido. Infelizmente, quando associamos diferentes ligações no mesmo elemento, não existe nenhuma forma ou local no editor gráfico onde podemos verificar a ordem da associação, à semelhança do que acontece com as functoids. A única forma de verificarmos a ordem nestes casos é inspeccionar o código XSLT gerado ou testando o mapa. Um bom exemplo deste cenário é quando associamos duas Scripting functoid com diferentes inline XSLT scripts ao mesmo destino, uma vez mais a troca na associação poderá ter resultados inesperados.
"Cliente"
Pessoa
Nome
><
"Nome/text()"
/></
Sexo
"Sexo/text()"
Em resumo, o motor de mapas processa as “regras” percorrendo o esquema de destino do início ao fim, processando as ligações pela ordem que os encontra e em caso de múltiplas ligações num determinado elemento ou functoid, as mesmas são processados pela ordem de associação. Isto significa que as ligações associadas aos nós pais são processadas antes das ligações associadas aos filhos. Um exemplo deste cenário é o uso de condições no nó pai quando pretendemos condicionar o resultado final segundo uma determinada condição. Vamos então procurar todos os nomes dos clientes do sexo feminino. Para isso iremos criar um mapa com as seguintes configurações:
A “Equal Functoid” vai retornar o valor “True” se o elemento “Sexo” for igual a “F”, caso contrário será retornado o valor “False”. O que origina que o nó “Pessoa” só é mapeado se o valor retornado for igual a “True”, obtendo assim a condição que pretendíamos. Se verificarmos o código gerado:
xsl:template
match
"/s0:Origem"
ns0:Destino
"userCSharp:LogicalEq(string(Sexo/text()) , "
F")" />
"$var:v1"
xmlns:ns0
"http://ComoFuncinamOsMapas.Schema2"
>Elsa Ligia</
int
contador = 0;
public
void
IncrementarContador()
{
contador += 1;
}
RetornarContador()
return
contador;
Linha
>0</
></
>1</
>2</
</ns0:Destino
"userCSharp:RetornarContador()"
"userCSharp:IncrementarContador()"
Sandro Pereira DevScope | MVP & MCTS BizTalk Server 2010 http://sandroaspbiztalkblog.wordpress.com/ | @sandro_asp
Carsten Siemens edited Revision 17. Comment: Added tags: pt-BR, has comment, has TOC
Sandro Pereira edited Revision 10. Comment: Finalização do documento
Sandro Pereira edited Revision 9. Comment: novo conteúdo e formatação dos scripts
Sandro Pereira edited Revision 8. Comment: Formatação dos scripts
Sandro Pereira edited Revision 7. Comment: Formatação dos scripts
Sandro Pereira edited Revision 5. Comment: Formatação do script: Morada