XML Mapper: Convertendo um XML genérico em Data Packet

Categoria: Artigos
Categoria Pai: Addicted 2 Delphi!
Acessos: 13134
Imagem meramente ilustrativa

O XML Mapper é um utilitário capaz de gerar arquivos de Transformação XML (no caso do XML Mapper, arquivos de extensão .xtr). Um arquivo de transformação, como o próprio nome sugere, é um arquivo capaz de transformar, ou traduzir um XLM, gerando como resultado um outro arquivo XML com estrutura específica ou mesmo outro formato, como HTML ou texto plano. No caso do XML Mapper, o arquivo de transformação será responsável por converter um XML qualquer em um XML Data Packet que é compatível com o TClientDataSet. Em outras palavras, usando a transformação XML gerada pelo XML Mapper é possível transformar um XML genérico em um XML específico para uso direto no TClientDataSet!

Como gerar um arquivo de transformação XML

Utilizar o XML Mapper pode parecer difícil a primeira vista, entretanto é bem mais fácil do que você pensa. Na verdade o único requisito para uso sem maiores problemas é que você saiba interpretar exatamente o XML original. É como a tradução de um texto em outro idioma: não adianta você saber traduzir as palavras individualmente, você precisa entender de fato o que está escrito a fim de fazer uma tradução bem feita.

Não pretendo neste artigo abordar todas as opções e possibilidades do XML Mapper. Cabe a você estudar o programa e descobrir todas as suas funcionalidades. O próprio XML Mapper possui um arquivo de ajuda facilmente acessível no seu menu Help. Não existe desculpa para não aprender.

Para seguir o passo-a-passo de geração de um arquivo de Transformação XML, anexado a este artigo está um XML simples. Abaixo está uma amostra da estrutura geral do arquivo, com apenas um item:

<Feriados>
	 <item>
		<id>638</id>
		<data>2017-07-16T00:00:00-03:00</data>
		<descricao>Dia da Padroeira Nossa Senhora do Carmo</descricao>
		<esfera>M</esfera>
		<dataFixa>S</dataFixa>
		<cidade>
		   <id>1</id>
		   <nome>Recife</nome>
		   <uf>PE</uf>
		   <regiaoMetropolitana>true</regiaoMetropolitana>
		</cidade>
	 </item>
</Feriados>

Como eu falei antes, é preciso entender o XML que se quer converter, por isso vou rapidamente explicar a estrutura do XML de exemplo: 

Este é um XML com os feriados do ano de 2017. O nó raiz é o nó <Feriados>, o qual contém vários nós de nome <item>. Cada um destes nós representa um feriado específico, logo, cada nó seria uma linha de nosso DataSet resultante. Cada linha, portanto, possui algumas colunas. No caso estas colunas são obtidas a partir dos nós <id>, <data>, <descricao>, <esfera>, <dataFixa> e <cidade>. O nó <cidade>, por sua vez, possui os subnós <id>, <nome>, <uf> e <regiaoMetropolitana>. O nó <cidade> é considerado no DataSet final como sendo um SubDataSet que é facilmente manipulado por qualquer TClientDataSet e pode ser renderizado em um segundo TDBGrid como um DataSet de detalhe! Quero ressaltar que todo XML a ser transformado precisa de um nó raiz. A ausência desse nó impossibilita a utilização do XML Mapper.

 

Após o entendimento inicial da estrutura do XML de exemplo, vamos ao passo-a-passo para geração do arquivo de transformação XML:

  1. Abra o programa xmlmapper.exe, que está localizado na pasta bin do Delphi. A tela do XML Mapper é exibida a seguir:

  2. Acesse o menu File > Open e selecione o XML a ser processado. O XML será carregado na área da esquerda da tela (Document: Feriados.xml):

    Note que a estrutura do XML é apresentada em forma de árvore.

  3. Na estrutura do XML identifique os nós que representam sub-conjuntos de dados e, caso existam, selecione-os um a um e clique na aba Node Properties na parte de baixo da tela. No nosso exemplo apenas o nó <cidade> representa um SubDataSet, portanto, selecione-o e clique na aba Node Properties. Veja a imagem para maiores detalhes:

    Na aba Node Properties para o nó  existe uma propriedade chamada Nested (aninhado), como este nó representa um SubDataSet, significa que seus dados (subnós) estão aninhados, logo, a propriedade Nested para o nó  precisa ser configurada como True. Note que até mesmo o ícone que representa este nó foi alterado para identificar visualmente que se trata de um nó que aninha subnós. Note que este ícone é igual ao ícone do nó  e, de fato, se você acessar as propriedades do nó , verá que ele tem a propriedade Nested = True!

  4. Aproveitando que a aba Node Properties está ativa, é hora de configurar os nós que você deseja mapear. A configuração básica consiste em informar o tipo de dado que cada nó precisa ter quando for convertido em TField de um TClientDataSet. Abaixo está o exemplo de seleção de tipo para o nó :

    Este nó contém uma data logo, sua propriedade DataType é configurada como Date. Note também que, diferentemente do nó "aninhador" , existem várias propriedades disponíveis. Nós de dados realmente possuem mais opções as quais eu não vou explicar aqui. Por ora apenas a propriedade DataType precisa ser alterada. Outras propriedades podem se manter como estiverem.

    Repita este passo para todos os nós que você deseja mapear, alterando sua propriedade Data Type para corresponder ao tipo de dado correto após a transformação.

  5. Clique novamente na aba Mapping a fim de exibir o mapeamento, o qual você vai definir agora. Você deve executar um duplo clique em cada nó que você deseja transformar em TField. Selecione todos os nós aplicáveis, incluindo os nós aninhados em <cidade>:

    Na parte de cima da tela estão nós que selecionamos e que serão mapeados para campos (TFields) no DataSet final. Claro que você poderia ignorar completamente a transformação de nós aninhados em <cidade>, mas para manter o artigo abrangente eu considero que neste exemplo você deseja transformar todos os nós disponíveis. As opções que foram destacadas (parte de baixo da tela) são aquelas que precisam estar selecionadas para que a transformação funcione como queremos.

  6. Clique com o botão direito do mouse em uma área vazia na parte da tela que mostra a estrutura do seu XML e nom menu popup selecione Create DataPacket from XML:

    Ao clicar nesta opção o mapeamento será criado e a tela do XML Mapper vai refletir esta criação:

    Neste momento nenhum arquivo de transformação foi salvo. Ele ainda está na memória e para provar que a transformação está funcionando como deve, clique no botão Create and Test Transformation. A tela abaixo vai aparecer:

    Esta tela mostra a visualização em um grid dos dados que estão no XML original, utilizando um arquivo de transformação XML na memória! Perceba que a coluna cidade é diferente; ela representa um SubDataSet. Clicando no botão de reticências vai exibir um outro grid com os registros deste SubDataSet. No nosso XML de exemplo, existem apenas 2 registros que contém dados no SubDataSet, eles se encontram no final do grid. Veja abaixo a exibição dos subregistros:

    Você pode inclusive navegar por entre os registros e perceber que o comportamento é de um relacionamento Mestre/Detalhe, ou seja, ao selecionar os registros 638 e 639 o grid que contém o SubDataSet vai mostrar os registros de detalhe!

  7. Salve o arquivo de transformação. Para fazer isso, clique com o botão direito do mouse numa área vazia da parte central da tela do XML Mapper e, no popup, clique no item Save Transformation:

    Escolha um nome de arquivo e salve o arquivo .xtr em um local pertinente. Eu recomendo usar o padrão sugerido (ToDp.xtr), que significa To DataPacket, indicando que trata-se de um arquivo de transformação usado para converter para um DataPacket.

  8. Salve o XML de definição dos campos. Este XML é um DataPacket sem dados, apenas com a estrutura. Ele será necessário para a criação dos campos persistentes. Para salvar este DataPacket, clique com o botão direito do mouse numa área vazia da parte direita da tela do XML Mapper e, no popup, clique no item Save DataPacket:

    Escolha um nome de arquivo e salve o arquivo .xml em um local pertinente. Eu recomendo salvar este arquivo com o mesmo nome do arquivo xml original, acrescido do sufixo DP (Feriados2017DP.xml)

Após executar estes 8 passos, você concluiu a criação e o teste do arquivo de Transformação XML. Agora vamos aprender a usar este arquivo no Delphi :)


Como utilizar um arquivo de transformação XML

Como exemplo de utilização do arquivo de transformação vamos supor que precisemos exibir os dados contidos no arquivo XML em um programa Delphi. Como nosso conjunto de dados resultante contém um relacionamento mestre/detalhe, o exemplo será composto de dois TDBGrid e um botão que fará o carregamento.

Para começar, crie uma aplicação VCL vazia, e inclua no TForm os dois TDBGrid, dois TClientDataSet, dois TDataSource e um TButton. A tela em tempo de desenvolvimento deve ficar assim:

Renomeie os dois TDBGrid de forma que o de cima seja DBGRMestre e o de baixo seja DBGRDetalhe. Renomeie o botão como BUTNCarregar. Ligue os componentes normalmente: TDBGrid + TDataSource + TClientDataSet. Clique com o botão direito do mouse em CLDSMestre, selecione a opção Load from MyBase table... e carregue o arquivo de definição (Feriados2017DP.xml). Nesse momento o TClientDataSet será aberto (Active = true), mas não conterá qualquer registro, porque o XML carregado contém apenas a definição dos campos.

O próximo passo é executar um duplo clique neste mesmo TClientDataSet (CLDSMestre) para exibir o Fields Editor o qual estará vazio. Clique com o botão direito na área vazia do Fields Editor e selecione a opção Add all fields. Neste momento todos os campos persistentes serão criados, incluindo o campo especial cidade, do tipo TDataSetField:

Agora selecione o segundo TClientDataSet (CLDSDetalhe), e configure sua propriedade DataSetField de forma que ele seja o campo cidade de CLDSMestre. Se você criou os campos automaticamente e não renomeou nenhum deles, a única opção disponível para escolha será CLDSMestrecidade, que é o campo persistente cidade de CLDSMestre.

Ao realizar a configuração da propriedade DataSetField em CLDSDetalhe, ele será automaticamente aberto. Neste momento você já deve ter notado que, em tempo de desenvolvimento, os TDBGrid já mostram as colunas tanto do CLDSMestre, quanto do CLDSDetalhe:


Apesar de isso parecer bom, vamos fechar os TClientDataSet pois é uma boa prática manter todos os DataSets sempre fechados. Para fazer isso, basta fechar CLDSMestre, pois CLDSDetalhe faz parte de CLDSMestre. Ao fazer isso as colunas dos dois TDBGrids vão sumir e isso é natural, pois elas estavam sendo criadas dinamicamente após a abertura dos TClientDataSets. Para manter as colunas visíveis mesmo após o fechamento dos TClientDataSets, execute um duplo clique em cada TDBGrid a fim de exibir o Columns editor e nele, clique no botão Add All Fields. Veja a figura abaixo, onde o botão Add All Fields encontra-se destacado e as colunas estão criadas:

Agora é hora de criar o código que faz a mágica acontecer. Coloque os arquivos xml e xtr na mesma pasta onde está sendo gerado seu executável. O arquivo XML é o arquivo original o qual você quer carregar (feriados2017.xml) e o arquivo XTR é o arquivo de transformação XML que você criou na seção anterior.

Todo o código será posto no evento OnClick do botão BTNCarregar. Segue o código completo:

procedure TForm1.BUTNCarregarClick(Sender: TObject);
var
  XMLTransform: TXMLTransform;
begin
  XMLTransform := TXMLTransform.Create(Self);
  try
    XMLTransform.SourceXmlFile := ExtractFilePath(ParamStr(0)) + 'Feriados2017.xml';
    XMLTransform.TransformationFile := ExtractFilePath(ParamStr(0)) + 'ToDp.xtr';
    CLDSMestre.XMLData := XMLTransform.Data;
  finally
    XMLTransform.Free;
  end;
end;

Este código que já é minúsculo ficaria ainda menor se eu tivesse usado o componente TXMLTransform de forma visual. Eu decidi criá-lo dinamicamente apenas para que vocês entendam melhor o que ele faz. Na linha 5 instanciamos o componente de transformação. Na linha 7 informamos ao componente qual o XML que será transformado. Na linha 8 informamos ao componente qual é o arquivo de transformação XML. Na linha 9 nós atribuímos o valor da propriedade Data do componente de transformação à propriedade XMLData do Client DataSet mestre. Esta linha faz duas coisas ao mesmo tempo. Primeiramente, ao ler o valor da propriedade Data, automaticamente é feita a transformação do XML original e o valor da propriedade Data é um XML DataPacket correspondente. Em segundo lugar, ao atribuir esse valor à propriedade XMLData do Client DataSet o mesmo é automaticamente aberto (Active = true). A linha 11, finalmente, destrói o componente de transformação, que não é mais necessário.

Onde está o componente TXMLTransform?

Como eu disse anteriormente eu decidi não usar o componente TXMLTransform, mas mesmo assim eu fui conferir suas propriedades e não o encontrei na paleta de componentes. Eu tinha certeza que ele existia e por isso fiz uma busca e descobri que o pacote que faz este e outros componentes para manipulação de XML aparecerem não estava registrado na IDE. Estou usando Delphi XE5 e não sei porque ele estava assim, mas a solução foi muito simples. Acessei Components > Install Packages na IDE, cliquei o botão Add... e selecionei o BPL dclwbm190.bpl que registrou o pacote Embarcadero InternetExpress Components, o qual contém o componente :)

Se seu Delphi não for o XE5 e você não estiver achando este componente, procure pelo BPL adequado trocando o número pelo correspondente para seu Delphi. Se você não sabe qual é o número que corresponde ao seu Delphi, eu recomendo o artigo Diretivas de compilação e versões do Delphi. Nele, há uma tabela em cuja coluna Library Suffix / Package Version estão os números das versões dos pacotes. Use-a para identificar a versão correta para seu Delphi e assim buscar o BPL correto.

O caminho oposto...

Se você analisou bem o XML Mapper enquanto o usava, deve ter se perguntado ou desconfiado se não seria possível transformar os dados de um DataPacket em um XML qualquer e a resposta, claro, é sim! Isso não será abordado aqui, mas fique sabendo que com um pouco de dedicação é perfeitamente possível fazer algo que, por exemplo, receba o resultado de um WebService, liste-o em um TDBGrid e, posteriormente envie esse resultado de volta, modificado, ao WebService. É claro que isso dá um pouco de trabalho, mas é perfeitamente viável!


  Arquivos anexados  
Arquivo Descrição Tamanho Modificado em
Download this file (Feriados2017.xml) Feriados2017.xml Arquivo de dados com os feriados do ano de 2017 6 KB 29/07/2017 às 18:08
Download this file (ToDp.xtr) ToDp.xtr Arquivo de transformação XML, usado para converter o arquivo Feriados2017.xml em um XML DataPacket compatível com o TClientDataSet 5 KB 29/07/2017 às 18:09