Difference between revisions of "XML Tutorial/es"
Line 209: | Line 209: | ||
</delphi> | </delphi> | ||
− | === | + | === Crear un TXMLDocument desde una cadena de caracteres === |
− | | + | Si MiCadenaXML contiene un documento XML, el código siguiente creará su DOM: |
<delphi> | <delphi> | ||
Var | Var | ||
− | + | Cadena: TStringStream; | |
XML : TXMLDocument; | XML : TXMLDocument; | ||
begin | begin | ||
− | + | Cadena:= TStringStream.Create(MiCadenaXML ); | |
Try | Try | ||
− | + | Cadena.Position:=0; | |
XML:=Nil; | XML:=Nil; | ||
− | ReadXMLFile(XML, | + | ReadXMLFile(XML,Cadena); // El documento XML completo |
// Alternatively: | // Alternatively: | ||
− | ReadXMLFragment( | + | ReadXMLFragment(UnNodoPadre,Cadena); // Lee únicamente un fragmento del XML |
Finally | Finally | ||
− | + | Cadena.Free; | |
end; | end; | ||
end; | end; |
Revision as of 23:56, 17 December 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) │
Introducción
El Lenguaje de Marcas Extensible (XML) es recomendado por el W3C y fue creado para el intercambio de información entre sistemas diferentes. Utiliza texto para almacenar la información. Lenguajes modernos de intercambio de datos, como XHTML y muchas tecnologías de servicios WEB están basados en XML.
Actualmente hay un conjunto de unidades que dan soporte a XML en Free Pascal. Estas unidades son "XMLRead", "XMLWrite" y "DOM" y son parte de FCL del compilador Free Pascal. las unidades de la FCL están en el ruta de búsqueda por defecto del compilador de Lazarus, por lo que sólo tendrá que añadir las unidades a la cláusula uses para utilizar XML. La FCL no está actualmente documentada completamente (Octubre / 2005), por lo que este breve tutorial tiene por objeto realizar una introducción al acceso a ficheros XML utilizando las unidades mencionadas.
El Modelo de Objeto de Documento (DOM) de XML es un conjunto normalizado de objetos que proporcionan una interfaz similar para el uso de XML en diferentes lenguajes y sistemas. La norma sólo especifica los métodos, propiedades y otras partes de la interfaz del objeto, dejando la implementación libre para los diferentes ilenguajes. El FCL actualmente apoya plenamente DOM XML 1.0.
Ejemplos
Lo que sigue son ejemplos de manipulación de datos XML con una complejidad creciente.
Leyendo un nodo de texto
Para programadores Delphi:
Resaltar que cuándo se trabaja con TXMLDocument, el texto en un nodo es considerado un nodo de Texto separado. Por tanto se accede al texto del nodo en un nodo separado. Alternativamente, la propiedad TextContent puede utilizarse para recuperar el contenido de todos los nodos de texto por debajo de uno dado, concatenados todos ellos.
El procedimiento ReadXMLFile crea siempre un nuevo objeto TXMLDocument, por lo que no hay que crearlo previamente de forma manual. Hay que asegurarse de destruir el documento llamando a Free cuando ya no lo necesitemos.
Por ejemplo, veamos el siguiente XML:
<xml>
<?xml version="1.0"?> <solicitud> <tipo_solicitud>PUT_FILE</tipo_solicitud> <usuario>123</usuario> <contrasenya>abc</contrasenya> </solicitud>
</xml>
Este ejemplo muestra la forma correcta y la incorrecta para obtener el valor textual de un nodo:
<delphi>
var NodoContra: TDOMNode; Doc: TXMLDocument; begin // leer archivo XMl desde disco ReadXMLFile(Doc, 'c:\archivos_xml\prueba.xml'); // Extraer el nodo "contrasenya" NodoContra := Doc.DocumentElement.FindNode('contrasenya'); // Escribir el valor del nodo elegido WriteLn(NodoContra.NodeValue); // estará vacío // El texto del nodo es un nodo hijo en este momento WriteLn(NodoContra.FirstChild.NodeValue); // Presenta "abc", tal como deseábamos // alternativamente WriteLn(NodoContra.TextContent); // Y para terminar liberar la memoria que ocupa nuestro objeto Doc Doc.Free;
end; </delphi>
Imprimir los nombres de los nodos
Brevemente, cómo recorrer el árbol DOM: Cuándo es necasario recorrer los nodos secuencialmente, lo mejor es utilizar las propiedades FirstChild y NextSibling, para avanzar en el árbol y las propiedades LastChild y PreviousSibling para recorrer el árbol de forma inversa. para acceder de forma aleatoria a nodos podemos utilizar los métodos ChildNodes o GetElementsByTagName, con lo que crearemos un objeto TDOMNodeList que debe ser liberado llegado el caso. La implementación DOM de FCL es orientada a objetos, frente a otras, como MSXML, que lo son orientadas a interfaz.
Este ejemplo muestra cómo mostrar los nombres de los nodos en un TMemo.
Este es el XML, en el archivo 'C:\Programas\prueba.xml':
<xml>
<?xml version="1.0"?> <imagenes directorio="midir"> <imagenesNodo URL="grafico.jpg" rotulo=""> <Trozo DestinoX="0" DestinoY="0">Trozocastillo.jpg1.swf</Trozo> <Trozo DestinoX="0" DestinoY="86">Trozocastillo.jpg2.swf</Trozo> </imagenesNodo> </imagenes>
</xml>
Y aquí el código Pascal para realizar el trabajo:
<delphi>
var Documento : TXMLDocument; Hijo : TDOMNode; j: Integer; begin ReadXMLFile(Documento, 'C:\Programas\prueba.xml'); Memo.Lines.Clear; // usando las propiedades FirstChild y NextSibling Hijo := Documento.DocumentElement.FirstChild; while Assigned(Hijo) do begin Memo.Lines.Add(Hijo.NodeName + ' ' + Hijo.Attributes.Item[0].NodeValue); // using ChildNodes method with Hijo.ChildNodes do try for j := 0 to (Count - 1) do Memo1.Lines.Add(Item[j].NodeName + ': ' + Item[j].FirstChild.NodeValue); finally Free; end; Hijo := Hijo.NextSibling; end; Documento.Free; end;
</delphi>
El resultado en Memo1 es:
imagenesNodo: grafico.jpg Trozo: Trozocastillo.jpg1.swf Trozo: PTrozocastillo.jpg1.swf
(re)Poblando un TreeView con XML
Es habitual procesar los archivos XML para mostrar su contenido en forma de árbol. El componente TTreeView se localiza en la pestaña "Common Controls" de Lazarus.
El código que se muestra toma un documento XML, previamente leído desde un archivo o generado por código, y con su contenido crea un árbol, en un TreeView. La etiqueta de cada nodo será el contenido del primer atributo de cada nodo XML.
<delphi> procedure TFormulario1.XML2Arbol(arbol: TTreeView; XMLDoc: TXMLDocument); var
iNodo: TDOMNode;
procedure ProcesaNodo(Nodo: TDOMNode; NodoArbol: TTreeNode); var cNodo: TDOMNode; begin if Nodo = nil then Exit; // Parar // Añadir nodo al árbol NodoArbol := arbol.Items.AddChild(NodoArbol, Nodo.Attributes[0].NodeValue);
// ir al nodo hijo cNodo := Nodo.FirstChild;
// Procesar todos los nodos hijos while cNodo <> nil do begin ProcesaNodo(cNodo, NodoArbol; cNodo := cNodo.NextSibling; end; end;
begin
iNodo := XMLDoc.DocumentElement.FirstChild; while iNodo <> nil do begin ProcesaNodo(iNodo, nil); // Recursivo iNodo := iNodo.NextSibling; end;
end; </delphi>
Modificando un documento XML
La primera cuestión que hay que recordar es que un TDOMDocument es un manejador del DOM. Podemos obtener una instancia, un objeto, de esta clase creando una explícitamente o bien cargando un documento XML.
Para crear nodos XML se deben utilizar los métodos provistos por TDOMDocument y trás ello utilizar el método adecuado para ubicar el nodo en el sitio deseado en el árbol XML. Esto se debe a que un nodo debe ser propiedad de un documento concreto del DOM.
A continuación se presentan algunos métodos comunes de TDOMDocument:
<delphi>
function CreateElement(const EtiquetaNombre: DOMString): TDOMElement; virtual; function CreateTextNode(const Datos: DOMString): TDOMText; function CreateCDATASection(const Datos: DOMString): TDOMCDATASection; virtual; function CreateAttribute(const nombre: DOMString): TDOMAttr; virtual;
</delphi>
Este es un ejemplo de cómo ubicar el elemento seleccionado en un TTreeView e insertar el nodo hijo que representa en el documento XML. El árbol debe ser previamente cumplimentado con el contenido del archivo XML utilizando la función XML2Tree.
<delphi> procedure TForm1.actAnyadeNodoHijo(Remitente: TObject); var
posicion: Integer; NeoNodo: TDomNode;
begin
{******************************************************************* * Hallar el elemento seleccionado *******************************************************************} if TreeView1.Selected = nil then Exit;
if TreeView1.Selected.Level = 0 then begin posicion := TreeView1.Selected.Index;
NeoNodo := XMLDoc.CreateElement('elemento'); TDOMElement(NovoNo).SetAttribute('nombre', 'Elemento'); TDOMElement(NovoNo).SetAttribute('archivo', 'Archivo'); with XMLDoc.DocumentElement.ChildNodes do begin Item[position].AppendChild(NeoNodo); Free; end;
{******************************************************************* * Actualiza el árbol TreeView1 *******************************************************************} TreeView1.Items.Clear; XML2Tree(TreeView1, XMLDoc); end else if TreeView1.Selected.Level >= 1 then begin {******************************************************************* * Esta función únicamente trabaja en el primer nivel del árbol. * pero puede ser fácilmente modificada para que lo haga en cualesquiera niveles *******************************************************************} end;
end; </delphi>
Crear un TXMLDocument desde una cadena de caracteres
Si MiCadenaXML contiene un documento XML, el código siguiente creará su DOM:
<delphi> Var
Cadena: TStringStream; XML : TXMLDocument;
begin
Cadena:= TStringStream.Create(MiCadenaXML ); Try Cadena.Position:=0; XML:=Nil; ReadXMLFile(XML,Cadena); // El documento XML completo // Alternatively: ReadXMLFragment(UnNodoPadre,Cadena); // Lee únicamente un fragmento del XML Finally Cadena.Free; end;
end; </delphi>
Validating a document
Since March 2007, DTD validation facility has been added to the FCL XML parser. Validation is checking that logical structure of the document conforms to the predefined rules, called Document Type Definition (DTD).
Here is an example of XML document with a DTD:
<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>
</xml>
This DTD specifies that 'root' element must have one or more 'child' elements, and that 'child' elements may have only character data inside. If parser detects any violations from these rules, it will report them.
Loading such document is slightly more complicated. Let's assume we have XML data in a TStream object:
<delphi> procedure TMyObject.DOMFromStream(AStream: TStream); var
Parser: TDOMParser; Src: TXMLInputSource; TheDoc: TXMLDocument;
begin
// create a parser object Parser := TDOMParser.Create; // and the input source Src := TXMLInputSource.Create(AStream); // we want validation Parser.Options.Validate := True; // assign a error handler which will receive notifications Parser.OnError := @ErrorHandler; // now do the job Parser.Parse(Src, TheDoc); // ...and cleanup Src.Free; Parser.Free;
end;
procedure TMyObject.ErrorHandler(E: EXMLReadError); begin
if E.Severity = esError then // we are interested in validation errors only writeln(E.Message);
end; </delphi>
Generating a XML file
Below is the complete code to write in a XML file. (This was taken from a tutorial in DeveLazarus blog ) Please, remember DOM and XMLWrite libs in uses clause
<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; // variable to document RootNode, parentNode, nofilho: TDOMNode; // variable to nodes
begin
//create a document xdoc := TXMLDocument.create;
//create a root node RootNode := xdoc.CreateElement('register'); Xdoc.Appendchild(RootNode); // save root node
//create a parent node RootNode:= xdoc.DocumentElement; parentNode := xdoc.CreateElement('usuario'); TDOMElement(parentNode).SetAttribute('id', '001'); // create atributes to parent node RootNode.Appendchild(parentNode); // save parent node
//create a child node parentNode := xdoc.CreateElement('nome'); // create a child node //TDOMElement(parentNode).SetAttribute('sexo', 'M'); // create atributes nofilho := xdoc.CreateTextNode('Fernando'); // insert a value to node parentNode.Appendchild(nofilho); // save node RootNode.ChildNodes.Item[0].AppendChild(parentNode); // insert child node in respective parent node
//create a child node parentNode := xdoc.CreateElement('idade'); // create a child node //TDOMElement(parentNode).SetAttribute('ano', '1976'); // create atributes nofilho := xdoc.CreateTextNode('32'); // insert a value to node parentNode.Appendchild(nofilho); // save node .ChildNodes.Item[0].AppendChild(parentNode); // insert a childnode in respective parent node
writeXMLFile(xDoc,'teste.xml'); // write to XML Xdoc.free; // free memory
end;
initialization
{$I unit1.lrs}
end. </delphi>
The result will be the XML file below: <xml> <?xml version="1.0"?> <register>
<usuario id="001"> <nome>Fernando</nome> <idade>32</idade> </usuario>
</register> </xml>
- Fernandosinesio 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com
- Versión en castellano (español) iskraelectrica (jldc) /diciembre de 2008.
Encoding
According to the XML standard, although there may be an encoding attribute in the first line of the XML, there is no need for it. As of version 0.9.26 of Lazarus, there is an encoding property in a TXMLDocument, but it is ignored. writeXMLFile always uses UTF-8 and doesn´t generate an encoding attribute in first line of the XML file.
External Links
- W3Schools Xml Tutorial
- Thomas Zastrow article FPC and XML