XML Tutorial/pt

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) magyar (hu) Bahasa Indonesia (id) italiano (it) 日本語 (ja) 한국어 (ko) português (pt) русский (ru) 中文(中国大陆)‎ (zh_CN)

Introdução

A "Extensible Markup Language" é uma linguagem recomendada pela W3C criada para a troca de informações entre diferentes sistemas. É um formato baseado em texto para armazenar informações. Linguagens modernas de troca de dados, como XHTML, bem como a maioria das tecnologia de WebServices, são baseados no XML.

Atualmente há um conjunto de units que fornecem suporte para o XML no Free Pascal. Estas units são chamadas "XMLRead", "XMLWrite" e "DOM" e elas são parte da Biblioteca de Componentes Livre (FCL) do compilador Free Pascal. A FCL já esta presente no caminho de busca (search path) padrão para o compilador no Lazarus, assim você só precisa adicionar as units na claúsula uses para ter suporte ao XML. A FCL não está com sua documentação atualizada (Outubro/2005), assim este pequeno tutorial é uma introdução ao acesso a XML usando estas units.

O XML DOM (Modelo Objeto de Documento) é um conjunto objetos padronizados que fornece uma interface similar para uso em diferentes linguagens e sistemas. O padrão só especifica os métodos, propriedades e outras partes da interface do objeto, deixando a implementação liberada para diferentes linguagens. A FCL atualmente tem suporte completo a DOM 1.0.

Exemplos

A seguir tem uma lista de exemplos de manipulação de dados XML com complexidade crescente.

Lendo um nó de texto (text node)

Para programadores Delphi: Note que, quando trabalha-se com TXMLDocument, o texto dentro de um Nó é considerado um nó de TEXTO separado. Como resultado, você deve acessar o valor do

texto do nó como um nó separado. Como alternativa, a propriedade TextContent pode ser usada para extrair o conteúdo de todos os nós de textos abaixo do

nó dado, com ambos concatenados.

A procedure ReadXMLFile sempre cria um novo TXMLDocument, assim você não tem que criá-lo com antecedência. Entretanto, tenha certeza de destruir

o documento chamando Free quando você terminar.

Por exemplo, considere o seguinte XML:

<xml>

<?xml version="1.0" encoding="utf-8"?>
<request>
  <request_type>PUT_FILE</request_type>
  <username>123</username>
  <password>abc</password>
</request>

</xml>

O seguinte exemplo de código mostra ambas as formas (correta e incorreta) de pegar o valor do nó de texto:

<delphi>

var
 PassNode: TDOMNode;
 Doc:      TXMLDocument;
begin
 // Lê no arquivo xml no disco
 ReadXMLFile(Doc, 'c:\xmlfiles\test.xml');
 // Extrai o nó "password"
 PassNode := Doc.DocumentElement.FindNode('password');
 // Escreve por extenso o valor do nó selecionado
 WriteLn(PassNode.NodeValue); // will be blank
 // O texto do nó é atualmente um "nó filho" separado
 WriteLn(PassNode.FirstChild.NodeValue); // correctly prints "abc"
 // como alternativa
 WriteLn(PassNode.TextContent);
 // finalmente, libera o documento
 Doc.Free;

end; </delphi>

Mostrando os nomes dos nós

Uma nota rápida na navegação pela árvore DOM: Quando você precisar acessar nós em seqüencia, é melhor usar as propriedades FirstChild e

NextSibling (para métodos GetElementsByTagName, mas esses serão criados um objeto TDOMNodeList que deverá ser eventualmente liberado. Isso difere

das outras implementações DOM como MSXML, porque a implementação feita pela FCL é baseada em objeto, não baseada na interface (interface-based).

Os seguintes exemplos demonstram como mostrar os nomes dos nodes para um TMemo localizado em um formulário.

A seguir o arquivo XML chamado 'C:\Programas\teste.xml':

<xml>

<?xml version="1.0" encoding="ISO-8859-1"?>
<images directory="mydir">
 <imageNode URL="graphic.jpg" title="">
   <Peca DestinoX="0" DestinoY="0">Pecacastelo.jpg1.swf</Peca>
   <Peca DestinoX="0" DestinoY="86">Pecacastelo.jpg2.swf</Peca>
 </imageNode>
</images>

</xml>

E aqui o código Pascal para executar a tarefa:

<delphi>

var
  Documento: TXMLDocument;
  Child: TDOMNode;
  j: Integer;
begin
  ReadXMLFile(Documento, 'C:\Programas\teste.xml');
  Memo.Lines.Clear;
  // usando as propriedades FirstChild e NextSibling
  Child := Documento.DocumentElement.FirstChild;
  while Assigned(Child) do
  begin
    Memo.Lines.Add(Child.NodeName + ' ' + Child.Attributes.Item[0].NodeValue);
    // usando método ChildNodes
    with Child.ChildNodes do
    try
      for j := 0 to (Count - 1) do
        Memo.Lines.Add(Item[j].NodeName + ' ' + Item[j].FirstChild.NodeValue);
    finally
      Free;
    end;
    Child := Child.NextSibling;
  end;
  Documento.Free;
end;

</delphi>

Isso mostrará:

imageNode graphic.jpg
Peca Pecacastelo.jpg1.swf
Peca Pecacastelo.jpg1.swf

Povoando um TreeView com XML

Um uso comum de arquivos XML é analisá-los e mostrar seu conteúdo em uma árvore como formato. Você pode encontrar o componente TTreeView na aba/guia "Common

Controls" do Lazarus.

A função a seguir pegará um documento XML, previamente carregado de um arquivo ou genrado em código, e povoará um TreeView com seu conteúdo. O caption de

cada nó consistirá no conteúdo do primeiro atributo de cada nó.

<delphi> procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); var

 iNode: TDOMNode;
 procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode);
 var
   cNode: TDOMNode;
 begin
   if Node = nil then Exit; // Pára, se atingir a folha
   
   // Adiciona um nó para a árvore
   TreeNode := tree.Items.AddChild(TreeNode, Node.Attributes[0].NodeValue);
   // Vai para o primeiro nó filho
   cNode := Node.FirstChild;
   // Processa todos os nós filhos
   while cNode <> nil do
   begin
     ProcessNode(cNode, TreeNode);
     cNode := cNode.NextSibling;
   end;
 end;
   

begin

 iNode := XMLDoc.DocumentElement.FirstChild;
 while iNode <> nil do
 begin
   ProcessNode(iNode, nil); // Recursivo
   iNode := iNode.NextSibling;
 end;

end; </delphi>

Modificando um documento XML

A primeira coisa a ser lembrada é que TDOMDocumento é o "handle" para o DOM. Você pode pegar uma instância dessa classe criando uma ou carregando um

documento XML.

Nós, por outro lado, não podem ser criados como um objeto normal. Você *deve* usar os métodos fornecidos por TDOMDocumento para criá-los, e posteriormente

usar outros métodos para colocá-los no lugar correto na árvore. Isso ocorre porque os nós devem ser "pertencentes" a um documento específico no DOM.

A seguir alguns métodos comuns de TDOMDocument:

<delphi>

  function CreateElement(const tagName: DOMString): TDOMElement; virtual;
  function CreateTextNode(const data: DOMString): TDOMText;
  function CreateCDATASection(const data: DOMString): TDOMCDATASection;
    virtual;
  function CreateAttribute(const name: DOMString): TDOMAttr; virtual;

</delphi>

E aqui um método de exemplo que localizará o item selelcionado em um TTreeView e inseri-rá um nó filho para o documento XML que ele representa. O TreeView

deve ser previamente preenchido com o conteúdo de um arquivo XML usando a função XML2Tree.

<delphi> procedure TForm1.actAddChildNode(Sender: TObject); var

 Posicao: Integer;
 NovoNo: TDomNode;

begin

 {*******************************************************************
 *  Detecta o elemento selecionado
 *******************************************************************}
 if TreeView1.Selected = nil then Exit;
 if TreeView1.Selected.Level = 0 then
 begin
   Posicao := TreeView1.Selected.Index;
   NovoNo := XMLDoc.CreateElement('item');
   TDOMElement(NovoNo).SetAttribute('nome', 'Item');
   TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
   with XMLDoc.DocumentElement.ChildNodes do
   begin
     Item[Posicao].AppendChild(NovoNo);
     Free;
   end;
   {*******************************************************************
   *  Atualiza o TreeView
   *******************************************************************}
   TreeView1.Items.Clear;
   XML2Tree(TreeView1, XMLDoc);
 end
 else if TreeView1.Selected.Level >= 1 then
 begin
   {*******************************************************************
   *  Essa função funciona somente no primeiro nível da árvore,
   *  mas pode facilmente ser modificada para funcionar em quaisquer outros níveis
   *******************************************************************}
 end;

end; </delphi>

Criar um TXMLDocument de um string

Dado um arquivo XML em MyXmlString, o seguinte código criará esse DOM:

<delphi> Var

 S : TStringStream;
 XML : TXMLDocument;

begin

 S:= TStringStream.Create(MyXMLString);
 Try
   S.Position:=0;
   XML:=Nil;
   ReadXMLFile(XML,S); // Completa o documento XML
   // Alternativamente:
   ReadXMLFragment(AParentNode,S); // Lê somente um fragmento XML.
 Finally
   S.Free;
 end;

end; </delphi>

Validando um documento

Desde Março de 2007, DTD validation facility foi adicionado para o analisador XML da FCL. A validação é a verificação da estrutura lógica do documento

conforme as regras pré-definidas, chamadas Documento Type Definition (DTD).

Aqui está um exemplo de um documento XML com um DTD:

<xml>

 <?xml version='1.0' encoding='utf-8'?>
 <!DOCTYPE root [
 <!ELEMENT root (child)+ >
 <!ELEMENT child (#PCDATA)>
 ]>
 <root>
   <child>This is a first child.</child>
   <child>And this is the second one.</child>
 </root>

</xml>

Esse DTD especifica que o elemento 'root' (raiz) deve ter um ou mais elementos 'child' (filho), e que os elementos 'child' pode ter somente dados de

caractere dentro. Se a análise deteca quaisquer violação dessas regras, ela reportará essas violações.

Carregar o documento dessa forma é um pouco mais complicado. Assumiremos que temos dados XML em um objeto TStream:

<delphi> procedure TMyObject.DOMFromStream(AStream: TStream); var

 Parser: TDOMParser;
 Src: TXMLInputSource;
 TheDoc: TXMLDocument;

begin

 // cria um objeto analisador
 Parser := TDOMParser.Create;
 // e a fonte de entrada
 Src := TXMLInputSource.Create(AStream);
 // nós queremos a validação
 Parser.Options.Validate := True;
 // associa um manipulador de erro que receberá as notificações
 Parser.OnError := @ErrorHandler;
 // agora faz o trabalho
 Parser.Parse(Src, TheDoc);
 // ...e limpeza total
 Src.Free;
 Parser.Free;

end;

procedure TMyObject.ErrorHandler(E: EXMLReadError); begin

 if E.Severity = esError then  // nós estamos interessados somente em erros de validação
   writeln(E.Message);

end; </delphi>

Gerando um arquivo XML

Abaixo um código completo para escrever em arquivo XML. Você pode ler o tutorial completo no blog da DeveLazarus (veja Links Externos) Por favor, lembre das bibliotecas DOM e XMLWrite na cláusula uses

<delphi> unit Unit1;

{$mode objfpc}{$H+}

interface

uses

 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
 DOM, XMLWrite;

type

 { TForm1 }
 TForm1 = class(TForm)
   Button1: TButton;
   Label1: TLabel;
   Label2: TLabel;
   procedure Button1Click(Sender: TObject);
 private
   { private declarations }
 public
   { public declarations }
 end;
 

var

 Form1: TForm1;
 

implementation

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject); var

 xdoc: TXMLDocument;                                  // variável para o documento
 noraiz, nopai, nofilho: TDOMNode;                    // variáveis dos nós

begin

 //cria um documento
 xdoc := TXMLDocument.create;
 //cria nó raiz
 noraiz := xdoc.CreateElement('cadastro');
 Xdoc.Appendchild(noraiz);                           // salva nó raiz
 //cria nó pai
 noraiz:= xdoc.DocumentElement;
 nopai := xdoc.CreateElement('usuario');
 TDOMElement(nopai).SetAttribute('id', '001');       // cria atributo para o nó pai
 noraiz.Appendchild(nopai);                          // salva o nó pai
 //cria nó filho
 nopai := xdoc.CreateElement('nome');                // cria o nó filho
 //TDOMElement(nopai).SetAttribute('sexo', 'M');     // cria atributo
 nofilho := xdoc.CreateTextNode('Fernando');         // insere um valor para o nó
 nopai.Appendchild(nofilho);                         // salva nó
 noraiz.ChildNodes.Item[0].AppendChild(nopai);       // insere o nó filho no nó pai correspondente
 //cria nó filho
 nopai := xdoc.CreateElement('idade');               // cria nó filho
 //TDOMElement(nopai).SetAttribute('ano', '1976');   // cria atributo
 nofilho := xdoc.CreateTextNode('32');               // coloca um valor ao nó
 nopai.Appendchild(nofilho);                         // salva o nó
 noraiz.ChildNodes.Item[0].AppendChild(nopai);       // insere o nó filho no nó pai correspondente
 writeXMLFile(xDoc,'teste.xml');                     // escreve o XML
 Xdoc.free;                                          // libera memória

end;

initialization

 {$I unit1.lrs}

end. </delphi>

Resulta no seguinte arquivo XML:

<xml>

<?xml version="1.0" ?> 
- <cadastro>
  - <usuario id="001">
      <nome>Fernando</nome> 
      <idade>32</idade> 
    </usuario>
  </cadastro>

</xml>

--Fernandosinesio 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com

Links Externos