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