XML Tutorial/pt
│
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
- W3Schools Tutorial Xml
- Thomas Zastrow article FPC e XML