Difference between revisions of "XML Tutorial/es"

From Lazarus wiki
Jump to navigationJump to search
m
Line 33: Line 33:
 
</xml>
 
</xml>
  
Este ejemplo muestra la forma correcta y la incorrecta para obtener el valor textual de un nodo:
+
&nbsp;&nbsp;&nbsp;Este ejemplo muestra la forma correcta y la incorrecta para obtener el valor textual de un nodo:
  
 
<delphi>
 
<delphi>
Line 57: Line 57:
 
=== Imprimir los nombres de los nodos ===
 
=== 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.
+
&nbsp;&nbsp;&nbsp;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.
+
&nbsp;&nbsp;&nbsp;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':
+
&nbsp;&nbsp;&nbsp;Este es el XML, en el archivo  'C:\Programas\prueba.xml':
  
 
<xml>
 
<xml>
Line 73: Line 73:
 
</xml>
 
</xml>
  
Y aquí el código Pascal para realizar el trabajo:
+
&nbsp;&nbsp;&nbsp;Y aquí el código Pascal para realizar el trabajo:
  
 
<delphi>
 
<delphi>
Line 102: Line 102:
 
</delphi>
 
</delphi>
  
El resultado en Memo1 es:
+
&nbsp;&nbsp;&nbsp;El resultado en Memo1 es:
  
 
<pre>
 
<pre>
Line 112: Line 112:
 
=== Poblando un '''TreeView''' con XML ===
 
=== 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.
+
&nbsp;&nbsp;&nbsp;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.
+
&nbsp;&nbsp;&nbsp;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>
 
<delphi>
Line 153: Line 153:
 
=== Modifying a XML document ===
 
=== Modifying a XML document ===
  
The first thing to remember is that TDOMDocument is the "handle" to the DOM. You can get an instance of this class by creating one or by loading a XML document.
+
&nbsp;&nbsp;&nbsp;The first thing to remember is that TDOMDocument is the "handle" to the DOM. You can get an instance of this class by creating one or by loading a XML document.
  
Nodes on the other hand cannot be created like a normal object. You *must* use the methods provided by TDOMDocument to create them, and latter use other methods to put them on the correct place on the tree. This is because nodes must be "owned" by a specific document on DOM.
+
&nbsp;&nbsp;&nbsp;Nodes on the other hand cannot be created like a normal object. You *must* use the methods provided by TDOMDocument to create them, and latter use other methods to put them on the correct place on the tree. This is because nodes must be "owned" by a specific document on DOM.
  
Below are some common methods from TDOMDocument:
+
&nbsp;&nbsp;&nbsp;Below are some common methods from TDOMDocument:
  
 
<delphi>
 
<delphi>
Line 167: Line 167:
 
</delphi>
 
</delphi>
  
And here an example method that will locate the selected item on a TTreeView and then insert a child node to the XML document it represents. The TreeView must be previously filled with the contents of a XML file using the [[Networking#Populating a TreeView with XML|XML2Tree function]].
+
&nbsp;&nbsp;&nbsp;And here an example method that will locate the selected item on a TTreeView and then insert a child node to the XML document it represents. The TreeView must be previously filled with the contents of a XML file using the [[Networking#Populating a TreeView with XML|XML2Tree function]].
  
 
<delphi>
 
<delphi>
Line 211: Line 211:
 
=== Create a TXMLDocument from a string ===
 
=== Create a TXMLDocument from a string ===
  
Given al XML file in MyXmlString, the following code will create it's DOM:
+
&nbsp;&nbsp;&nbsp;Given al XML file in MyXmlString, the following code will create it's DOM:
  
 
<delphi>
 
<delphi>
Line 234: Line 234:
 
=== Validating a document ===
 
=== 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).
+
&nbsp;&nbsp;&nbsp;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:
+
&nbsp;&nbsp;&nbsp;Here is an example of XML document with a DTD:
  
 
<xml>
 
<xml>
Line 250: Line 250:
 
</xml>
 
</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.
+
&nbsp;&nbsp;&nbsp;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:
+
&nbsp;&nbsp;&nbsp;Loading such document is slightly more complicated. Let's assume we have XML data in a TStream object:
  
 
<delphi>
 
<delphi>
Line 285: Line 285:
 
=== Generating a XML file ===
 
=== Generating a XML file ===
  
Below is the complete code to write in a XML file.
+
&nbsp;&nbsp;&nbsp;Below is the complete code to write in a XML file.
(This was taken from a tutorial in DeveLazarus blog )
+
&nbsp;&nbsp;&nbsp;(This was taken from a tutorial in DeveLazarus blog )
Please, remember DOM and XMLWrite libs in uses clause
+
&nbsp;&nbsp;&nbsp;Please, remember DOM and XMLWrite libs in uses clause
  
 
<delphi>
 
<delphi>

Revision as of 23:17, 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

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
     ProceaNodo(cNodo, NodoArbol;
     cNodo := cNodo.NextSibling;
   end;
 end;
   

begin

 iNodo := XMLDoc.DocumentElement.FirstChild;
 while iNodeo <> nil do
 begin
   ProcesaNodo(iNodo, nil); // Recursivo
   iNodo := iNodo.NextSibling;
 end;

end; </delphi>

Modifying a XML document

   The first thing to remember is that TDOMDocument is the "handle" to the DOM. You can get an instance of this class by creating one or by loading a XML document.

   Nodes on the other hand cannot be created like a normal object. You *must* use the methods provided by TDOMDocument to create them, and latter use other methods to put them on the correct place on the tree. This is because nodes must be "owned" by a specific document on DOM.

   Below are some common methods from 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>

   And here an example method that will locate the selected item on a TTreeView and then insert a child node to the XML document it represents. The TreeView must be previously filled with the contents of a XML file using the XML2Tree function.

<delphi> procedure TForm1.actAddChildNode(Sender: TObject); var

 position: Integer;
 NovoNo: TDomNode;

begin

 {*******************************************************************
 *  Detects the selected element
 *******************************************************************}
 if TreeView1.Selected = nil then Exit;
 if TreeView1.Selected.Level = 0 then
 begin
   position := TreeView1.Selected.Index;
   NovoNo := XMLDoc.CreateElement('item');
   TDOMElement(NovoNo).SetAttribute('nome', 'Item');
   TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
   with XMLDoc.DocumentElement.ChildNodes do
   begin
     Item[position].AppendChild(NovoNo);
     Free;
   end;
   {*******************************************************************
   *  Updates the TreeView
   *******************************************************************}
   TreeView1.Items.Clear;
   XML2Tree(TreeView1, XMLDoc);
 end
 else if TreeView1.Selected.Level >= 1 then
 begin
   {*******************************************************************
   *  This function only works on the first level of the tree,
   *  but can easely modifyed to work for any number of levels
   *******************************************************************}
 end;

end; </delphi>

Create a TXMLDocument from a string

   Given al XML file in MyXmlString, the following code will create it's DOM:

<delphi> Var

 S : TStringStream;
 XML : TXMLDocument;

begin

 S:= TStringStream.Create(MyXMLString);
 Try
   S.Position:=0;
   XML:=Nil;
   ReadXMLFile(XML,S); // Complete XML document
   // Alternatively:
   ReadXMLFragment(AParentNode,S); // Read only XML fragment.
 Finally
   S.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>

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


Multithreaded Application Tutorial