Difference between revisions of "XML Tutorial/pt"

From Lazarus wiki
(Introdução)
(Lendo um nó de texto (text node))
Line 49: Line 49:
 
   PassNode := Doc.DocumentElement.FindNode('password');
 
   PassNode := Doc.DocumentElement.FindNode('password');
 
   // Escreve por extenso o valor do nó selecionado
 
   // Escreve por extenso o valor do nó selecionado
   WriteLn(PassNode.NodeValue); // will be blank
+
   WriteLn(PassNode.NodeValue); // estará em branco
 
   // O texto do nó é atualmente um "nó filho" separado
 
   // O texto do nó é atualmente um "nó filho" separado
   WriteLn(PassNode.FirstChild.NodeValue); // correctly prints "abc"
+
   WriteLn(PassNode.FirstChild.NodeValue); // mostra corretamente "abc"
 
   // como alternativa
 
   // como alternativa
 
   WriteLn(PassNode.TextContent);
 
   WriteLn(PassNode.TextContent);

Revision as of 22:45, 26 April 2008

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 XML 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); // estará em branco
 // O texto do nó é atualmente um "nó filho" separado
 WriteLn(PassNode.FirstChild.NodeValue); // mostra corretamente "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