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

7 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

Diga-nos, o que achou deste artigo?