Difference between revisions of "XML Tutorial/pt"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{XML Tutorial}}
 
{{XML Tutorial}}
  
=== Introdução ===
+
== Introdução ==
  
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.
+
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.
  
Atualmente há um conjunto de unidades que dão suporte para o XML no Lazarus. Estas unidades são "XMLRead", "XMLWrite" e "DOM" e elas são parte da Biblioteca de Componentes Livre(FCL) do compilador Free Pascal. A FCL esta sempre presente no caminho padrão para o compilador no Lazarus, então você somente precisa adicionar as unidades na claúsula uses para ter suporte ao XML. A FCL não está com sua documentação atualizada(desde outubro de 2005), então este curto tutorial é uma introdução ao acesso a XML usando estas unidades.
+
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 esta presente no caminho de busca (search path) padrão para o compilador no Lazarus, assim você 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 (Documento de Modelo do Objeto) é um conjunto padronizações de objetos que fornece uma interface para uso em diferentes linguagens e sistemas. O padrão somente especifica os métodos, propriedades e outras partes da interface do objeto, deixando a implementação livre para diferentes linguagens. A FCL atualmente suporta completamente a [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/|XML DOM 1.0].
+
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 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].
  
===Exemplo Básico===
+
== Exemplos ==
  
Vamos dizer que você precisa acessar um arquivo XML chamado: 'C:\Programas\teste.xml'. Aqui esta o conteúdo do arquivo:
+
A seguir tem uma lista de exemplos de manipulação de dados XML com complexidade crescente.
  
<code>
+
=== 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 21: Line 79:
 
   </imageNode>
 
   </imageNode>
 
  </images>
 
  </images>
</code>
+
</syntaxhighlight>
  
O seguinte código pode escrever o nome dos nós num objeto TMemo no formulário:
+
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
  ReadXMLFile(Documento, 'C:\Programas\teste.xml');
+
  ReadXMLFile(Documento, 'C:\Programas\teste.xml');
  Memo.Lines.Clear;
+
  Memo.Lines.Clear;
  with Documento.DocumentElement.ChildNodes do
+
  // 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;
 +
</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;
   Documento.Free;
+
end;
  end;
+
</syntaxhighlight>
</code>
+
 
 +
=== 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;
  
Código inteiro para escrever em arquivo XML:
+
{$mode objfpc}{$H+}
(Lembrar das  bibliotecas DOM e XMLWrite na cláusula uses)
 
  
unit Unit1;
+
interface
{$mode objfpc}{$H+}
 
interface
 
  
uses
+
uses
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, DOM, XMLWrite, StdCtrls;
+
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
 +
  DOM, XMLWrite;
  
type
+
type
 
   { TForm1 }
 
   { TForm1 }
 
   TForm1 = class(TForm)
 
   TForm1 = class(TForm)
Line 69: Line 333:
 
   public
 
   public
 
     { public declarations }
 
     { public declarations }
   end;  
+
   end;
var
+
 
   Form1: TForm1;  
+
var
implementation
+
   Form1: TForm1;
{ 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;
  
procedure TForm1.Button1Click(Sender: TObject);
+
  //cria nó raiz
   var
+
  noraiz := xdoc.CreateElement('cadastro');
    xdoc: TXMLDocument;                                  //variável para o documento
+
   Xdoc.Appendchild(noraiz);                           // salva nó raiz
    noraiz, nopai, nofilho: TDOMNode;                   //variáveis dos Nós
 
  
begin
+
  //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 um documento
+
  //cria nó filho
    xdoc := TXMLDocument.create;
+
  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ó raiz
+
  //cria nó filho
    noraiz := xdoc.CreateElement('cadastro');
+
  nopai := xdoc.CreateElement('idade');               // cria nó filho
    Xdoc.Appendchild(noraiz);                           //salva Nó raiz
+
  //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
  
    //cria Nó pai
+
  writeXMLFile(xDoc,'teste.xml');                     // escreve o XML
    noraiz:= xdoc.DocumentElement;
+
  Xdoc.free;                                         // libera memória
    nopai := xdoc.CreateElement('usuario');
+
end;
    TDOMElement(nopai).SetAttribute('id', '001');       //cria atributo para o Nó pai
 
    noraiz.Appendchild(nopai);                         //salva nó pai
 
  
    //cria Nó Filho
+
initialization
    nopai := xdoc.CreateElement('nome');                //cria Nó Filho
+
   {$I unit1.lrs}
    //TDOMElement(nofilho).SetAttribute('sexo', 'M');   //cria atributo
 
    nofilho := xdoc.CreateTextNode('Fernando');        //insere valor para o nó
 
    nopai.Appendchild(nofilho);                        //salva nó
 
    noraiz.ChildNodes.Item[0].AppendChild(nopai);      //insere o nó filho ao nó pai correspondente
 
  
    //cria Nó Filho
+
end.
    nopai := xdoc.CreateElement('idade');              //cria Nó Filho
+
</syntaxhighlight>
    //TDOMElement(nofilho).SetAttribute('ano', '1976'); //cria atributo
 
    nofilho := xdoc.CreateTextNode('32');              //insere coloca valor nó
 
    nopai.Appendchild(nofilho);                        //salva nó
 
    noraiz.ChildNodes.Item[0].AppendChild(nopai);      //insere o nó filho ao nó pai correspondente
 
  
    writeXMLFile(xDoc,'teste.xml');                    //escreve XML
+
Resulta no seguinte arquivo XML:
    Xdoc.free;                                          //libera memória
 
 
end;
 
 
initialization
 
{$I unit1.lrs}
 
 
end.
 
  
Resulta em:
+
<syntaxhighlight lang="xml">
   
+
  <?xml version="1.0" ?>  
    <?xml version="1.0" ?>  
+
- <cadastro>
  - <cadastro>
+
  - <usuario id="001">
    - <usuario id="001">
+
      <nome>Fernando</nome>  
        <nome>Fernando</nome>  
+
      <idade>32</idade>  
        <idade>32</idade>  
+
    </usuario>
      </usuario>
+
  </cadastro>
    </cadastro>
+
</syntaxhighlight>
 
baseado no site:                                                     
 
[http://develazarus.wordpress.com/2007/07/12/generando-un-archivo-xml/]
 
  
 
--[[User:Fernandosinesio|Fernandosinesio]] 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com
 
--[[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