Social Icons

segunda-feira, 6 de agosto de 2012

XML Data Bind no Delphi

Neste artigo vou ensinar como trabalhar com arquivos XMLs de uma forma sofisticada e de alto nível. Para melhor compreensão deste recurso recomendo a leitura dos artigos Manipulação de XML com TXMLDocument, Manipulação de XML com TXMLDocument – Parte 2 e Manipulação de XML com TXMLDocument – Parte 3. Também estou considerando que você tem uma noção básica sobre XML e XML Schema, mas caso não, recomendo as seções sobre XML e XML Schema do site w3schools.

Observação
Utilizaremos nos exemplos o delphi XE, no entanto o XML Data Bind existe desde o Delphi 6, as versões anteriores eu não conheço, assim não posso afirmar se existe ou não o recurso.

Usaremos para esse exemplo um arquivo XML que representa um pedido:

<?xml version="1.0" encoding="ISO-8859-1"?>
<shiporder orderid="889923" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="shiporder.biz">
  <orderperson>John Smith</orderperson>
  <shipto>
    <name>Ola Nordmann</name>
    <address>Langgt 23</address>
    <city>4000 Stavanger</city>
    <country>Norway</country>
  </shipto>
  <item>
    <title>Empire Burlesque</title>
    <note>Special Edition</note>
    <quantity>1</quantity>
    <price>10.90</price>
  </item>
  <item>
    <title>Hide your heart</title>
    <quantity>1</quantity>
    <price>9.90</price>
  </item>
</shiporder>

shiporder Elemento raiz que representa o pedido, ele possui o atributo orderid que possui o código do pedido
orderperson Pessoa que fez o pedido
shipto Dados de entrega
  • name: Pessoa que receberá o pedido
  • adress: Endereço de entrega
  • city: Cidade de entrega
  • country: Pais de entrega
item Dados do produto no pedido
  • title: Descrição do produto
  • note: Observação do produto
  • price: Preço do produto 
  • quantity: Quantidade do produto no pedido

Para definir a estrutura e restrições do XML temos o seguinte XML Schema que é chamado de XSD (XML Schema Definition).

<?xml version="1.0" encoding="ISO-8859-1" ?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stringtype">
  <xs:restriction base="xs:string"/>
</xs:simpleType>

<xs:simpleType name="inttype">
  <xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>

<xs:simpleType name="dectype">
  <xs:restriction base="xs:decimal"/>
</xs:simpleType>

<xs:simpleType name="orderidtype">
  <xs:restriction base="xs:string">
    <xs:pattern value="[0-9]{6}"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="shiptotype">
  <xs:sequence>
    <xs:element name="name" type="stringtype"/>
    <xs:element name="address" type="stringtype"/>
    <xs:element name="city" type="stringtype"/>
    <xs:element name="country" type="stringtype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="itemtype">
  <xs:sequence>
    <xs:element name="title" type="stringtype"/>
    <xs:element name="note" type="stringtype" minOccurs="0"/>
    <xs:element name="quantity" type="inttype"/>
    <xs:element name="price" type="dectype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="shipordertype">
  <xs:sequence>
    <xs:element name="orderperson" type="stringtype"/>
    <xs:element name="shipto" type="shiptotype"/>
    <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
  </xs:sequence>
  <xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>

<xs:element name="shiporder" type="shipordertype"/>

</xs:schema>

Importaremos o arquivo XSD usando o XMLDataBind do delphi que está em: File / New / Other / Delphi Projects / XML, para isso criemos uma nova aplicação no delphi.

tela5

Será apresentado um wizard do XML Data Bind. Informe o caminho do arquivo XSD

tela6

Atenção!
Nesse exemplo salvamos o arquivo XSD com a extensão .biz, pois o delphi XE não importa corretamente o arquivo se ele possuir a extensão .xsd

Ao clicar em avançar percebemos que na próxima tela foi gerada uma estrutura baseada no arquivo XSD, essas estruturas são interfaces e classes para facilitar a manipulação do XML. Nessa parte se desejar poderá fazer alterações nessas estruturas e interfaces.

tela7

Ao clicar novamente em avançar será mostrado uma outra tela com todo o código fonte que será gerado

tela8

Agora basta finalizar e salvar a unit gerada pelo wizard.

No TForm da sua aplicação coloque um TMemo, um open dialog e dois TButtons. No evento onClick de um dos TButtons coloque o seguinte código

procedure TForm1.Button1Click(Sender: TObject);
var
   pedido :IXMLShipordertype;
   item :IXMLItemtype;
   begin
   //Cria uma nova instância da estrutura de classes para criar um novo XML
   pedido := Newshiporder();
   
   //Informações do pedido
   pedido.Orderid := '123456';
   pedido.Orderperson := 'Livraria X';
   
   //Informações do destinatário do pedido
   pedido.Shipto.Name := 'Jocimar B. A. Huss ';
   pedido.Shipto.Address := 'R. Carapicuiba 23';
   pedido.Shipto.City := 'Mandaguari PR';
   pedido.Shipto.Country := 'Brasil';

   //Inclui um novo item ao pedido<
   item := pedido.Item.Add;
   item.Title := 'Programacacao em Delphi';
   item.Quantity := 4;
   item.Price := '102,33';
   item.Note := 'Nao aborda versoes mais antigas da IDE delphi';
   
   //Inclui um novo item ao pedido
   item := pedido.Item.Add;
   item.Title := 'Programacacao em Java - Iniciante';
   item.Quantity := 1;
   item.Price := '140,00';
   item.Note := 'Somente o basico do java';
   
   Memo1.Text :=  pedido.XML;

   memo1.Lines.SaveToFile(ExtractFilePath(Application.ExeName) + 'shiporder.xml');
end;

No evento onClick do outro TButton coloque o seguinte código

procedure TForm1.Button2Click(Sender: TObject);
var
   pedido :IXMLShipordertype;
      i :Integer;
begin
   OpenDialog1.InitialDir := ExtractFilePath(Application.ExeName);
   
   //Pergunta qual arquivo xml deseja abrir
   if not OpenDialog1.Execute then
      exit;
   
   //Cria uma nova instância da estrutura de classes para fazermos o bind
   pedido := Loadshiporder(OpenDialog1.FileName);
   
   memo1.Clear;
   
   //Informações do pedido
   memo1.Lines.Add('[Informações do pedido]');
   memo1.Lines.Add('Código do pedido: ' + pedido.Orderid)
   memo1.Lines.Add('Pessoa do Pedido: '+pedido.Orderperson);
   
   memo1.Lines.Add('');
   memo1.Lines.Add('[Dados do destinatário do pedido]');
   
   //Infomações do destinatário do pedido
   memo1.Lines.Add('Nome: ' + pedido.Shipto.Name);
   memo1.Lines.Add('Endereço: ' + pedido.Shipto.Address);
   memo1.Lines.Add('Cidade: ' + pedido.Shipto.City);
   memo1.Lines.Add('Pais: ' + pedido.Shipto.Country);
   memo1.Lines.Add('');
   
   //Inclui um novo item ao pedido
   memo1.Lines.Add('[Itens do pedido]');
   for i := 0 to pedido.Item.Count - 1 do
   begin
     memo1.Lines.Add('Titulo: ' + pedido.Item[i].Title);
     memo1.Lines.Add('Quantidade: ' + IntToStr(pedido.Item[i].Quantity));
     memo1.Lines.Add('Preço: ' + pedido.Item[i].Price);
     memo1.Lines.Add('Observação: ' + pedido.Item[i].Note);
     
     memo1.Lines.Add('');
   end;
end;

Pronto, o exemplo já conseguimos gerar um XML e ler um XML gerado na estrutura definida pelo XSD de exemplo. Bom é isso aí, caso tenham dúvidas postem na seção de comentários.

Atenção!
Caso o XML gerado possuir acentos ou outro caractere especial, acontecerá um erro ao carrega-lo. Não pude resolver esse problema, pois não  consegui informar o Encoding do XML.

Baixe os fontes do artigo no GitHub

11 comentários:

  1. Como faço para colocar o "encoding" no meu novo documento? Alias, muito bom o artigo ^^

    ResponderExcluir
  2. Como faço a engenharia reversa? A partir das clases geradas pelo xml dta binding, regerar o xsd? Eu não tenho o xsd que gerou as classes e preciso editar/incluir campos no layout do xml. Obrigado

    ResponderExcluir
    Respostas
    1. Este comentário foi removido pelo autor.

      Excluir
    2. Não conheço conheço recurso para fazer a leitura das classes e gerar o XSD, mas é possível que exista, se eu descobrir alguma coisa, postarei aqui no blog.

      Excluir
  3. Este comentário foi removido pelo autor.

    ResponderExcluir
    Respostas
    1. Olá Alexandre. Newshiporder foi criado quando importamos o xsd. Basicamente essa importação do xsd mapeia classes no delphi para a estrutura do xml de exemplo que usamos. Assim facilitando a geração e alteração se um xml. A importação de xsd jà existe desde a versão 6 do Delphi.

      Excluir
    2. Obrigado Jocimar, Acabei encontrando as Globais, por algum motivo na primeira tentativa que fiz o delphi não as havia gerado, o que naturalmente gerou erro. Mas depois tentei novamente e deu certo.

      Excluir
  4. Bom dia. Valeu demais pelo artigo. Ajudou em um projeto que eu não estava sabendo nem errar.

    ResponderExcluir
  5. Este comentário foi removido pelo autor.

    ResponderExcluir
  6. Boa Noite Pessoal, Jocimar parabéns pelo Artigo

    ResponderExcluir

Diga-nos, o que achou deste artigo?