Difference between revisions of "XML Tutorial/pt"

From Lazarus wiki
Jump to navigationJump to search
(New page: ==XML== A "Extensible Markup Language" é uma linguagem recomendada pela [http://www.w3.org/ W3C] para a troca de informações entre diferentes sistemas. É um formato baseado em texto d...)
 
m (Fixed syntax highlighting)
 
(21 intermediate revisions by 7 users not shown)
Line 1: Line 1:
==XML==
+
{{XML Tutorial}}
  
A "Extensible Markup Language" é uma linguagem recomendada pela [http://www.w3.org/ W3C] para a troca de informações entre diferentes sistemas. É um formato baseado em texto de guardar informações. Linguagens modernas de troca de dados, como o XHTML, além da maioria das tecnologia de WebServices, são baseados no XML.
+
== Introdução ==
  
Currently there is a set of units that provides support for XML on Lazarus. These units are called "XMLRead", "XMLWrite" and "DOM" and they are part of the Free Component Library (FCL) from the Free Pascal Compiler. The FCL is already on the default search path for the compiler on Lazarus, so you only need to add the units to your uses clause in order to get XML support. The FCL is not documented currently (October / 2005), so this short tutorial aims at introducing XML access using those units.
+
A "Extensible Markup Language" é uma linguagem recomendada pela [http://www.w3.org/ 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.
  
The XML DOM (Document Object Model) is a set of standarized objects that provide a similar interface for the use of XML on different languages and systems. The standard only specifies the methods, properties and other interface parts of the object, leaving the implementation free for different languages. The FCL currently supports fully the [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/|XML DOM 1.0].
+
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.
  
===Basic Example===
+
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 [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/ XML DOM 1.0].
  
Let´s say you want to access a XML file called 'C:\Programas\teste.xml'. Here is the file content:
+
== Exemplos ==
  
<code>
+
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:
 +
 
 +
<syntaxhighlight lang="xml">
 +
<?xml version="1.0"?>
 +
<request>
 +
  <request_type>PUT_FILE</request_type>
 +
  <username>123</username>
 +
  <password>abc</password>
 +
</request>
 +
</syntaxhighlight>
 +
 
 +
O seguinte exemplo de código mostra ambas as formas (correta e incorreta) de pegar o valor do nó de texto:
 +
 
 +
<syntaxhighlight lang=pascal>
 +
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;
 +
</syntaxhighlight>
 +
 
 +
=== 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':
 +
 
 +
<syntaxhighlight lang="xml">
 
  <?xml version="1.0"?>
 
  <?xml version="1.0"?>
 
  <images directory="mydir">
 
  <images directory="mydir">
Line 19: Line 79:
 
   </imageNode>
 
   </imageNode>
 
  </images>
 
  </images>
</code>
+
</syntaxhighlight>
  
The following code can write the Node´s names to a TMemo placed on a form:
+
E aqui o código Pascal para executar a tarefa:
  
<code>
+
<syntaxhighlight lang=pascal>
 
  var
 
  var
  Documento: TXMLDocument;
+
  Documento: TXMLDocument;
  i, j: Integer;
+
  Child: TDOMNode;
 +
  j: Integer;
 
  begin
 
  begin
  Documento := TXMLDocument.Create;
+
  ReadXMLFile(Documento, 'C:\Programas\teste.xml');
  ReadXMLFile(Documento, 'C:\Programas\teste.xml');
+
  Memo.Lines.Clear;
  Memo.Lines.Clear;
+
  // usando as propriedades FirstChild e NextSibling
  with Documento.DocumentElement.ChildNodes do
+
  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;
 +
</syntaxhighlight>
 +
 
 +
Isso mostrará:
 +
 
 +
<pre>
 +
imageNode graphic.jpg
 +
Peca Pecacastelo.jpg1.swf
 +
Peca Pecacastelo.jpg1.swf
 +
</pre>
 +
 
 +
=== 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ó.
 +
 
 +
<syntaxhighlight lang=pascal>
 +
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;
 +
</syntaxhighlight>
 +
 
 +
=== 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:
 +
 
 +
<syntaxhighlight lang=pascal>
 +
  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;
 +
</syntaxhighlight>
 +
 
 +
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 [[Networking#Populating a TreeView with XML|função XML2Tree]].
 +
 
 +
<syntaxhighlight lang=pascal>
 +
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
 
   begin
     for i := 0 to (Count - 1) do
+
     Posicao := TreeView1.Selected.Index;
 +
 
 +
    NovoNo := XMLDoc.CreateElement('item');
 +
    TDOMElement(NovoNo).SetAttribute('nome', 'Item');
 +
    TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
 +
    with XMLDoc.DocumentElement.ChildNodes do
 
     begin
 
     begin
       Memo.Lines.Add(Item[i].NodeName + ' ' + Item[i].NodeValue);
+
       Item[Posicao].AppendChild(NovoNo);
      for j := 0 to (Item[i].ChildNodes.Count - 1) do
+
       Free;
      begin
 
        Memo.Lines.Add(Item[i].ChildNodes.Item[j].NodeName + ' '
 
        + Item[i].ChildNodes.Item[j].NodeValue);
 
       end;
 
 
     end;
 
     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;
 +
</syntaxhighlight>
 +
 +
=== Criar um TXMLDocument de um string ===
 +
 +
Dado um arquivo XML em MyXmlString, o seguinte código criará esse DOM:
 +
 +
<syntaxhighlight lang=pascal>
 +
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;
 +
</syntaxhighlight>
 +
 +
=== 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:
 +
 +
<syntaxhighlight lang="xml">
 +
  <?xml version='1.0'?>
 +
  <!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>
 +
</syntaxhighlight>
 +
 +
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:
 +
 +
<syntaxhighlight lang=pascal>
 +
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;
 +
</syntaxhighlight>
 +
 +
=== 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 [[XML_Tutorial/pt#Links Externos|Links Externos]])
 +
Por favor, lembre das  bibliotecas DOM e XMLWrite na cláusula uses
 +
 +
<syntaxhighlight lang=pascal>
 +
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;
 
   end;
   Documento.Free;
+
    
end;
+
var
</code>
+
  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.
 +
</syntaxhighlight>
 +
 
 +
Resulta no seguinte arquivo XML:
 +
 
 +
<syntaxhighlight lang="xml">
 +
<?xml version="1.0" ?>
 +
- <cadastro>
 +
  - <usuario id="001">
 +
      <nome>Fernando</nome>
 +
      <idade>32</idade>
 +
    </usuario>
 +
  </cadastro>
 +
</syntaxhighlight>
 +
 
 +
--[[User:Fernandosinesio|Fernandosinesio]] 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com
 +
 
 +
== Links Externos ==
 +
 
 +
* [http://www.w3schools.com/xml/default.asp W3Schools] Tutorial Xml
 +
 
 +
* [http://www.thomas-zastrow.de/texte/fpcxml/index.php Thomas Zastrow article] FPC e XML
 +
 
 +
* [http://develazarus.wordpress.com/2007/07/12/generando-un-archivo-xml/ Gerando um arquivo XML (Espanhol)]

Latest revision as of 03:49, 2 March 2020

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 version="1.0"?>
 <request>
   <request_type>PUT_FILE</request_type>
   <username>123</username>
   <password>abc</password>
 </request>

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

 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;

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 version="1.0"?>
 <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>

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

 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;

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ó.

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;

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:

   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;

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.

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;

Criar um TXMLDocument de um string

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

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;

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 version='1.0'?>
  <!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>

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:

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;

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

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.

Resulta no seguinte arquivo XML:

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

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

Links Externos