Difference between revisions of "XML Tutorial/es"

From Lazarus wiki
Jump to navigationJump to search
m
m (Fixed syntax highlighting)
 
(40 intermediate revisions by 5 users not shown)
Line 5: Line 5:
 
   El Lenguaje de Marcas Extensible  (XML) es recomendado por el [http://www.w3.org/ 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.
 
   El Lenguaje de Marcas Extensible  (XML) es recomendado por el [http://www.w3.org/ 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.
+
   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  la 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 [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/ DOM XML 1.0].
+
   El '''M'''odelo de '''O'''bjeto de '''D'''ocumento (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 [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/ DOM XML 1.0].
  
 
== Ejemplos ==
 
== Ejemplos ==
  
 
+
   Lo que sigue son ejemplos de manipulación de datos XML con una complejidad creciente. Las unidades necesarias para compilar los códigos de los  ejemplos (y para cualquier otro código con XML) son: DOM, XMLRead, XMLWrite, XMLCfg, XMLUtils, XMLStreaming. Aunque no todas son necesarias para todos los ejemplos.
   Lo que sigue son ejemplos de manipulación de datos XML con una complejidad creciente.
 
  
 
=== Leyendo un nodo de texto ===
 
=== Leyendo un nodo de texto ===
Line 24: Line 23:
 
    Por ejemplo, veamos el siguiente XML:
 
    Por ejemplo, veamos el siguiente XML:
  
<xml>
+
<syntaxhighlight lang="xml"> <?xml version="1.0"?>
<?xml version="1.0"?>
 
 
  <solicitud>
 
  <solicitud>
 
   <tipo_solicitud>PUT_FILE</tipo_solicitud>
 
   <tipo_solicitud>PUT_FILE</tipo_solicitud>
 
   <usuario>123</usuario>
 
   <usuario>123</usuario>
 
   <contrasenya>abc</contrasenya>
 
   <contrasenya>abc</contrasenya>
  </solicitud>
+
  </solicitud></syntaxhighlight>
</xml>
 
  
&nbsp;&nbsp;&nbsp;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 (no olvides añadir las unidades '''XMLRead''' and '''DOM''' en la sección '''uses'''):
  
<delphi>
+
<syntaxhighlight lang=pascal> var
var
 
 
  NodoContra: TDOMNode;
 
  NodoContra: TDOMNode;
 
   Doc:      TXMLDocument;
 
   Doc:      TXMLDocument;
 
  begin
 
  begin
   // leer archivo XMl desde disco
+
   try
  ReadXMLFile(Doc, 'c:\archivos_xml\prueba.xml');
+
  // leer archivo XMl desde disco
  // Extraer el nodo "contrasenya"
+
  ReadXMLFile(Doc, 'prueba.xml');
  NodoContra := Doc.DocumentElement.FindNode('contrasenya');
+
  // Extraer el nodo "contrasenya"
  // Escribir el valor del nodo elegido
+
  NodoContra := Doc.DocumentElement.FindNode('contrasenya');
  WriteLn(NodoContra.NodeValue); // estará vacío
+
  // Escribir el valor del nodo elegido
  // El texto del nodo es un nodo hijo en este momento
+
  WriteLn(NodoContra.NodeValue); // estará vacío
  WriteLn(NodoContra.FirstChild.NodeValue); // Presenta "abc", tal como deseábamos
+
  // El texto del nodo es un nodo hijo en este momento
  // alternativamente
+
  WriteLn(NodoContra.FirstChild.NodeValue); // Presenta "abc", tal como deseábamos
  WriteLn(NodoContra.TextContent);
+
  // alternativamente
   // Y para terminar liberar la memoria que ocupa nuestro objeto Doc
+
  WriteLn(NodoContra.TextContent);
  Doc.Free;
+
   finally
end;
+
  // Y para terminar liberar la memoria que ocupa nuestro objeto Doc
</delphi>
+
  Doc.Free;
 +
end;
 +
end;</syntaxhighlight>
  
=== Imprimir los nombres de los nodos ===
+
&nbsp;&nbsp;&nbsp;Ten en cuenta que ReadXMLFile (...) ignora todos los caracteres de espacios en blanco al analizar un documento. La sección [[#Espacios en Blanco | espacios en blanco]] se describe cómo conservarlos.
  
&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.
+
=== Imprimir los nombres de los nodos  y atributos===
 +
 
 +
&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.
  
 
&nbsp;&nbsp;&nbsp;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.
  
&nbsp;&nbsp;&nbsp;Este es el XML, en el archivo  'C:\Programas\prueba.xml':
+
&nbsp;&nbsp;&nbsp;Este es el XML, en el archivo  'prueba.xml':
  
<xml>
+
<syntaxhighlight lang="xml"> <?xml version="1.0"?>
<?xml version="1.0"?>
 
 
  <imagenes directorio="midir">
 
  <imagenes directorio="midir">
 
   <imagenesNodo URL="grafico.jpg" rotulo="">
 
   <imagenesNodo URL="grafico.jpg" rotulo="">
Line 70: Line 69:
 
     <Trozo DestinoX="0" DestinoY="86">Trozocastillo.jpg2.swf</Trozo>
 
     <Trozo DestinoX="0" DestinoY="86">Trozocastillo.jpg2.swf</Trozo>
 
   </imagenesNodo>
 
   </imagenesNodo>
  </imagenes>
+
  </imagenes></syntaxhighlight>
</xml>
 
  
 
&nbsp;&nbsp;&nbsp;Y aquí el código Pascal para realizar el trabajo:
 
&nbsp;&nbsp;&nbsp;Y aquí el código Pascal para realizar el trabajo:
  
<delphi>
+
<syntaxhighlight lang=pascal> var
var
 
 
   Documento : TXMLDocument;
 
   Documento : TXMLDocument;
 
   Hijo : TDOMNode;
 
   Hijo : TDOMNode;
 
   j: Integer;
 
   j: Integer;
 
  begin
 
  begin
   ReadXMLFile(Documento, 'C:\Programas\prueba.xml');
+
  try
 +
   ReadXMLFile(Documento, 'prueba.xml');
 
   Memo.Lines.Clear;
 
   Memo.Lines.Clear;
 
   // usando las propiedades FirstChild y NextSibling
 
   // usando las propiedades FirstChild y NextSibling
Line 92: Line 90:
 
     try
 
     try
 
       for j := 0 to (Count - 1) do
 
       for j := 0 to (Count - 1) do
         Memo1.Lines.Add(Item[j].NodeName + ': ' + Item[j].FirstChild.NodeValue);
+
         Memo.Lines.Add(format('%s %s (%s=%s; %s=%s)',
 +
[
 +
  Item[j].NodeName,
 +
  Item[j].FirstChild.NodeValue,
 +
  Item[j].Attributes.Item[0].NodeName, // detalles del primer atributo
 +
  Item[j].Attributes.Item[0].NodeValue,
 +
  Item[j].Attributes.Item[1].NodeName, // detalles del segundo atributo
 +
  Item[j].Attributes.Item[1].NodeValue
 +
]));
 
     finally
 
     finally
 
       Free;
 
       Free;
Line 98: Line 104:
 
     Hijo := Hijo.NextSibling;
 
     Hijo := Hijo.NextSibling;
 
   end;
 
   end;
 +
  finally
 
   Documento.Free;
 
   Documento.Free;
  end;
+
  end;
</delphi>
+
  end;</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;El resultado en Memo1 es:
 
&nbsp;&nbsp;&nbsp;El resultado en Memo1 es:
  
<pre>
+
<pre> imagenesNodo: grafico.jpg
imagenesNodo: grafico.jpg
+
Trozo: Trozocastillo.jpg1.swf (DestinoX=0; DestinoY=0)
Trozo: Trozocastillo.jpg1.swf
+
Trozo: PTrozocastillo.jpg2.swf (DestinoX=0; DestinoY=86)</pre>
Trozo: PTrozocastillo.jpg1.swf
 
</pre>
 
  
=== Poblando un '''TreeView''' con XML ===
+
=== (re)Poblando un '''TreeView''' con XML ===
  
 
&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.
 
&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.
Line 116: Line 121:
 
&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.
 
&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>
+
<syntaxhighlight lang=pascal> procedure TFormulario1.XML2Arbol(arbol: TTreeView; XMLDoc: TXMLDocument);
procedure TFormulario1.XML2Arbol(arbol: TTreeView; XMLDoc: TXMLDocument);
+
var
var
 
 
   iNodo: TDOMNode;
 
   iNodo: TDOMNode;
  
Line 124: Line 128:
 
   var
 
   var
 
     cNodo: TDOMNode;
 
     cNodo: TDOMNode;
 +
    s: string;
 
   begin
 
   begin
 
     if Nodo = nil then Exit; // Parar
 
     if Nodo = nil then Exit; // Parar
 
      
 
      
     // Añadir nodo al árbol
+
     // Añadir nodo al árbol, si tiene atributos
    NodoArbol := arbol.Items.AddChild(NodoArbol, Nodo.Attributes[0].NodeValue);
+
   
 +
      if Nodo.HasAttributes and (Nodo.Attributes.Length>0) then
 +
        s:=Nodo.Attributes[0].NodeValue
 +
      else
 +
        s:='';
 +
      TreeNode := tree.Items.AddChild(TreeNode, s);
  
 
     // ir al nodo hijo
 
     // ir al nodo hijo
Line 136: Line 146:
 
     while cNodo <> nil do
 
     while cNodo <> nil do
 
     begin
 
     begin
       ProceaNodo(cNodo, NodoArbol;
+
       ProcesaNodo(cNodo, NodoArbol;
 
       cNodo := cNodo.NextSibling;
 
       cNodo := cNodo.NextSibling;
 
     end;
 
     end;
 
   end;
 
   end;
 
      
 
      
begin
+
begin
 
   iNodo := XMLDoc.DocumentElement.FirstChild;
 
   iNodo := XMLDoc.DocumentElement.FirstChild;
   while iNodeo <> nil do
+
   while iNodo <> nil do
 
   begin
 
   begin
 
     ProcesaNodo(iNodo, nil); // Recursivo
 
     ProcesaNodo(iNodo, nil); // Recursivo
 
     iNodo := iNodo.NextSibling;
 
     iNodo := iNodo.NextSibling;
 
   end;
 
   end;
end;
+
end;</syntaxhighlight>
</delphi>
 
  
=== Modifying a XML document ===
+
&nbsp;&nbsp;&nbsp;Otro ejemplo que muestra la estructura completa de XML con todos los valores de atributos::
 +
<syntaxhighlight lang=pascal> procedure XML2Tree(XMLDoc:TXMLDocument; TreeView:TTreeView);
 +
 +
  // función local que extrae como texto todos los atributos de los nodos
 +
  function GetNodeAttributesAsString(pNode: TDOMNode):string;
 +
  var i: integer;
 +
  begin
 +
    Result:='';
 +
    if pNode.HasAttributes then
 +
      for i := 0 to pNode.Attributes.Length -1 do
 +
        with pNode.Attributes[i] do
 +
          Result := Result + format(' %s="%s"', [NodeName, NodeValue]);
 +
 +
    // Quita los epacios de principio y final
 +
    Result:=Trim(Result);
 +
  end;
 +
 +
  // Funcion recursiva que procesa un nodo y todos su nodos hijos
 +
  procedure ParseXML(Node:TDOMNode; TreeNode: TTreeNode);
 +
  begin
 +
    // Salir del procedimiento si no hay nodos para procesar
 +
    if Node = nil then Exit;
 +
 +
    // Añadir el nodo al arbol (TreeView)
 +
    TreeNode := TreeView.Items.AddChild(TreeNode,Trim(Node.NodeName+' '+GetNodeAttributesAsString(Node)+ Node.NodeValue));
 +
 +
    // Procesar todos los nodos hijos
 +
    Node := Node.FirstChild;
 +
    while Node <> Nil do
 +
    begin
 +
      ParseXML(Node, TreeNode);
 +
      Node := Node.NextSibling;
 +
    end;
 +
  end;
 +
 +
begin
 +
  TreeView.Items.Clear;
 +
  ParseXML(XMLDoc.DocumentElement,nil);
 +
end;</syntaxhighlight>
 +
 
 +
=== Modificando un documento XML ===
 +
 
 +
&nbsp;&nbsp;&nbsp;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.
 +
 
 +
&nbsp;&nbsp;&nbsp;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.
 +
 
 +
&nbsp;&nbsp;&nbsp;A continuación se presentan algunos métodos comunes de TDOMDocument:
 +
 
 +
<syntaxhighlight lang=pascal> 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;</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;<tt>CreateElement</tt> crea un nodo nuevo.
 +
 
 +
&nbsp;&nbsp;&nbsp;<tt>CreateTextNode</tt> crea un valor par un nodo.
  
&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.
+
&nbsp;&nbsp;&nbsp;<tt>CreateAttribute</tt> crea un atributo dentro de un nodo.
  
&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.
+
&nbsp;&nbsp;&nbsp;<tt>CreateCDATA</tt> crea una sección CDATA: Los caracteres habituales de marca de XML cómo <> no se interpretan dentro de la sección CDATA. Ver [https://secure.wikimedia.org/wikipedia/en/wiki/CDATA artículo sobre CDATA en la Wikipedia]
  
&nbsp;&nbsp;&nbsp;Below are some common methods from TDOMDocument:
+
&nbsp;&nbsp;&nbsp;Un método más adecuado para manipular atributos es utilizar el método <tt>TDOMElement.SetAttribute</tt>, que también se presenta como la propiedad predeterminada de <tt>TDOMElement</tt>:
  
<delphi>
+
<syntaxhighlight lang=pascal> // Estos dos elementos son equivalentes
  function CreateElement(const tagName: DOMString): TDOMElement; virtual;
+
Element.SetAttribute('nombre', 'valor');
  function CreateTextNode(const data: DOMString): TDOMText;
+
Element['nombre'] := 'valor'; </syntaxhighlight>
  function CreateCDATASection(const data: DOMString): TDOMCDATASection;
 
    virtual;
 
  function CreateAttribute(const name: DOMString): TDOMAttr; virtual;
 
</delphi>
 
  
&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]].
+
&nbsp;&nbsp;&nbsp;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 [[XML_Tutorial/es#.28re.29Poblando_un_TreeView_con_XML|la función XML2Tree]].
  
<delphi>
+
<syntaxhighlight lang=pascal> procedure TForm1.actAnyadeNodoHijo(Remitente: TObject);
procedure TForm1.actAddChildNode(Sender: TObject);
+
var
var
+
   posicion: Integer;
   position: Integer;
+
   NeoNodo: TDomNode;
   NovoNo: TDomNode;
+
begin
begin
 
 
   {*******************************************************************
 
   {*******************************************************************
   *  Detects the selected element
+
   *  Hallar el elemento seleccionado
 
   *******************************************************************}
 
   *******************************************************************}
 
   if TreeView1.Selected = nil then Exit;
 
   if TreeView1.Selected = nil then Exit;
Line 182: Line 241:
 
   if TreeView1.Selected.Level = 0 then
 
   if TreeView1.Selected.Level = 0 then
 
   begin
 
   begin
     position := TreeView1.Selected.Index;
+
     posicion := TreeView1.Selected.Index;
  
     NovoNo := XMLDoc.CreateElement('item');
+
     NeoNodo := XMLDoc.CreateElement('elemento');
     TDOMElement(NovoNo).SetAttribute('nome', 'Item');
+
     TDOMElement(NovoNo).SetAttribute('nombre', 'Elemento');
     TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
+
     TDOMElement(NovoNo).SetAttribute('archivo', 'Archivo');
 
     with XMLDoc.DocumentElement.ChildNodes do
 
     with XMLDoc.DocumentElement.ChildNodes do
 
     begin
 
     begin
       Item[position].AppendChild(NovoNo);
+
       Item[position].AppendChild(NeoNodo);
 
       Free;
 
       Free;
 
     end;
 
     end;
  
 
     {*******************************************************************
 
     {*******************************************************************
     *  Updates the TreeView
+
     *  Actualiza el árbol TreeView1
 
     *******************************************************************}
 
     *******************************************************************}
 
     TreeView1.Items.Clear;
 
     TreeView1.Items.Clear;
Line 202: Line 261:
 
   begin
 
   begin
 
     {*******************************************************************
 
     {*******************************************************************
     *  This function only works on the first level of the tree,
+
     *  Esta función únicamente trabaja en el primer nivel del árbol.
     *  but can easely modifyed to work for any number of levels
+
     *  pero puede ser fácilmente modificada para que lo haga en cualesquiera niveles
 
     *******************************************************************}
 
     *******************************************************************}
 
   end;
 
   end;
end;
+
end;</syntaxhighlight>
</delphi>
 
  
=== Create a TXMLDocument from a string ===
+
=== Crear un TXMLDocument desde una cadena de caracteres ===
  
&nbsp;&nbsp;&nbsp;Given al XML file in MyXmlString, the following code will create it's DOM:
+
&nbsp;&nbsp;&nbsp;Si MiCadenaXML contiene un documento XML, el código siguiente creará su DOM:
  
<delphi>
+
<syntaxhighlight lang=pascal> Var
Var
+
Cadena: TStringStream;
  S : TStringStream;
+
XML : TXMLDocument;
  XML : TXMLDocument;
 
  
begin
+
begin
   S:= TStringStream.Create(MyXMLString);
+
   Cadena:= TStringStream.Create(MiCadenaXML );
 
   Try
 
   Try
     S.Position:=0;
+
     Cadena.Position:=0;
 
     XML:=Nil;
 
     XML:=Nil;
     ReadXMLFile(XML,S); // Complete XML document
+
     ReadXMLFile(XML,Cadena); // El documento XML completo
 
     // Alternatively:
 
     // Alternatively:
     ReadXMLFragment(AParentNode,S); // Read only XML fragment.
+
     ReadXMLFragment(UnNodoPadre,Cadena); // Lee únicamente un fragmento del XML
 
   Finally
 
   Finally
     S.Free;
+
     Cadena.Free;
 
   end;
 
   end;
end;
+
end;</syntaxhighlight>
</delphi>
+
 
 +
=== Validando un documento ===
 +
 
 +
&nbsp;&nbsp;&nbsp;Desde marzo de 2007, la validación con DTD se ha añadido al analizador XML de la FCL. La validación verifica que la estructura lógica del documento se ajusta a las normas definidas en el DTD (Definición de Tipo de Documento) correspondiente.
 +
 
 +
&nbsp;&nbsp;&nbsp;Este es un ejemplo de un documento XML con DTD:
 +
 
 +
<syntaxhighlight lang="xml"> <?xml version='1.0'?>
 +
<!DOCTYPE raiz [
 +
<!ELEMENT raiz (child)+ >
 +
<!ELEMENT hijo (#PCDATA)>
 +
]>
 +
<raiz>
 +
  <hijo>Este es el primer hijo.</hijo>
 +
  <hijo>Y este el segundo.</hijo>
 +
</raiz></syntaxhighlight>
 +
 
 +
&nbsp;&nbsp;&nbsp;Este DTD especifica que el elemento 'raiz' puede tener uno o más elementos 'hijo', y que estos, los elementos 'hijo', únicamente pueden contener caracteres de datos. Si el analizador informa si detecta alguna violación de estas reglas .
  
=== Validating a document ===
+
&nbsp;&nbsp;&nbsp;Cargar un documento de esta forma es un poco más complicado. Supongamos que tenemos datos XML en un objeto TStream:
  
&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).
+
<syntaxhighlight lang=pascal> procedure TMiObjeto.DOMdesdeFlujo(unFlujo: TStream);
 +
var
 +
  Analizador : TDOMParser;
 +
  Fuente : TXMLInputSource;
 +
  Doc : TXMLDocument;
 +
begin
 +
  try
 +
  // creamos el objeto analizador
 +
  Analizador := TDOMParser.Create;
 +
  // y la fuente de entrada
 +
  Fuente := TXMLInputSource.Create(unFlujo);
 +
  // ahora validamos
 +
  Analizador.Options.Validate := True;
 +
  // asignamos un manejador de errores pra recibir las notificaciones
 +
  Analizador.OnError := @ErrorHandler;
 +
  // realizamos el trabajo
 +
  Analizador.Parse(Fuente, Doc);
 +
  // ...y hacemos limpieza (general)
 +
  finally
 +
  Fuente.Free;
 +
  Analizador.Free;
 +
  end;
 +
end;
  
&nbsp;&nbsp;&nbsp;Here is an example of XML document with a DTD:
+
procedure TMiObjeto.ErrorHandler(Error: EXMLReadError);
 +
begin
 +
  if Error.Severity = esError then  // únicamente nos interesan los errores de validación
 +
    writeln(Error.Message);
 +
end;</syntaxhighlight>
  
<xml>
+
=== Espacios en Blanco ===
  <?xml version='1.0'?>
+
&nbsp;&nbsp;&nbsp;Si deseas conservar los espacios en blanco al principio de los textos de un nodo, el método anterior es la forma de cargar el documento XML. Los espacios en blanco iniciales son ignorados por defecto. Esta es la razón por la cual la función ReadXML (...) nunca devuelve los espacios en blanco en textos nodo.
  <!DOCTYPE root [
+
&nbsp;&nbsp;&nbsp;Antes de llamar a ''Analizador.Parse(Fuente, Doc)'' inserta la línea
  <!ELEMENT root (child)+ >
 
  <!ELEMENT child (#PCDATA)>
 
  ]>
 
  <root>
 
    <child>This is a first child.</child>
 
    <child>And this is the second one.</child>
 
  </root>
 
</xml>
 
  
&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.
+
<syntaxhighlight lang=pascal> Analizador.Options.PreserveWhitespace := True;</syntaxhighlight>
  
&nbsp;&nbsp;&nbsp;Loading such document is slightly more complicated. Let's assume we have XML data in a TStream object:
+
&nbsp;&nbsp;&nbsp;Esto obliga a que el analizador devuelva todos los espacios en blanco. ¡Esto incluye también los caracteres de nueva línea que existen en un documento XML para que sea más fácil de leer!
  
<delphi>
+
=== Creando un documento XML ===
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);
+
&nbsp;&nbsp;&nbsp;A continuación se muestra el código completo para crear un documento XML y escribirlo en un archivo.
begin
 
  if E.Severity = esError then // we are interested in validation errors only
 
    writeln(E.Message);
 
end;
 
</delphi>
 
  
=== Generating a XML file ===
+
&nbsp;&nbsp;&nbsp;(Esto está tomado de un tutorial del blog '''DeveLazarus''')
  
&nbsp;&nbsp;&nbsp;Below is the complete code to write in a XML file.
+
&nbsp;&nbsp;&nbsp;Recuerda poner en la cláusula uses las unidades DOM y XMLWrite
&nbsp;&nbsp;&nbsp;(This was taken from a tutorial in DeveLazarus blog )
 
&nbsp;&nbsp;&nbsp;Please, remember DOM and XMLWrite libs in uses clause
 
  
<delphi>
+
<syntaxhighlight lang=pascal> unit Unidad1;
unit Unit1;
 
  
{$mode objfpc}{$H+}
+
{$mode objfpc}{$H+}
  
interface
+
interface
  
uses
+
uses
 
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
 
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
 
   DOM, XMLWrite;
 
   DOM, XMLWrite;
  
type
+
type
 
   { TForm1 }
 
   { TForm1 }
 
   TForm1 = class(TForm)
 
   TForm1 = class(TForm)
     Button1: TButton;
+
     Boton1: TButton;
     Label1: TLabel;
+
     Etiqueta1: TLabel;
     Label2: TLabel;
+
     Etiqueta2: TLabel;
     procedure Button1Click(Sender: TObject);
+
     procedure Boton1Click(Originador: TObject);
 
   private
 
   private
     { private declarations }
+
     { declaraciones privadas}
 
   public
 
   public
     { public declarations }
+
     { declaraciones publicas }
 
   end;
 
   end;
 
    
 
    
var
+
var
 
   Form1: TForm1;
 
   Form1: TForm1;
 
    
 
    
implementation
+
implementation
  
{ TForm1 }
+
{ TForm1 }
  
procedure TForm1.Button1Click(Sender: TObject);
+
procedure TForm1.Boton1Click(Originador : TObject);
var
+
var
   xdoc: TXMLDocument;                                  // variable to document
+
   xdoc: TXMLDocument;                                  // variable objeto documento XML
   RootNode, parentNode, nofilho: TDOMNode;                    // variable to nodes
+
   NodoRaiz, NodoPadre, NodoHijo: TDOMNode;                    // variables a los nodos
begin
+
begin
   //create a document
+
   //crear el documento
 
   xdoc := TXMLDocument.create;
 
   xdoc := TXMLDocument.create;
  
   //create a root node
+
   NodoRaiz := xdoc.CreateElement('registrar');     //crear el nodo raíz
  RootNode := xdoc.CreateElement('register');
+
   Xdoc.Appendchild(NodoRaiz);                          // guardar nodo raíz
   Xdoc.Appendchild(RootNode);                          // save root node
 
  
   //create a parent node
+
   NodoRaiz := xdoc.DocumentElement;   //crear el nodo padre
  RootNode:= xdoc.DocumentElement;
+
   NodoPadre := xdoc.CreateElement('usuario');
   parentNode := xdoc.CreateElement('usuario');
+
   TDOMElement(NodoPadre).SetAttribute('id', '001');      // crear los atributos del nodo padre
   TDOMElement(parentNode).SetAttribute('id', '001');      // create atributes to parent node
+
   NodoRaiz.Appendchild(NodoPadre);                          // guardar nodo padre
   RootNode.Appendchild(parentNode);                          // save parent node
 
  
   //create a child node
+
   NodoPadre := xdoc.CreateElement('nombre');                // crear el nodo hijo
  parentNode := xdoc.CreateElement('nome');                // create a child node
+
   //TDOMElement(NodoPadre).SetAttribute('sexo', 'M');    // crear los atributos
   //TDOMElement(parentNode).SetAttribute('sexo', 'M');    // create atributes
+
   NodoHijo := xdoc.CreateTextNode('Fernando');        // insertar el valor del nodo
   nofilho := xdoc.CreateTextNode('Fernando');        // insert a value to node
+
   NodoPadre.Appendchild(NodoHijo);                        // guardar nodo
   parentNode.Appendchild(nofilho);                        // save node
+
   NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre);      // insertar el nodo hijo en el correspondiente nodo padre
   RootNode.ChildNodes.Item[0].AppendChild(parentNode);      // insert child node in respective parent node
 
  
   //create a child node
+
   NodoPadre := xdoc.CreateElement('edad');              // crear el nodo hijo
  parentNode := xdoc.CreateElement('idade');              // create a child node
+
   //TDOMElement(NodoPadre).SetAttribute('anyo', '1976');  // crear los atributos
   //TDOMElement(parentNode).SetAttribute('ano', '1976');  // create atributes
+
   NodoHijo := xdoc.CreateTextNode('32');              // insertar el valor del nodo
   nofilho := xdoc.CreateTextNode('32');              // insert a value to node
+
   NodoPadre.Appendchild(NodoHijo);                        // guardar nodo
   parentNode.Appendchild(nofilho);                        // save node
+
   NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre);      // insertar el nodo hijo en el correspondiente nodo padre
   .ChildNodes.Item[0].AppendChild(parentNode);      // insert a childnode in respective parent node
 
  
   writeXMLFile(xDoc,'teste.xml');                    // write to XML
+
   writeXMLFile(xDoc,'prueba.xml');                    // escribir el XML
   Xdoc.free;                                          // free memory
+
   Xdoc.free;                                          // liberar la memoria
end;
+
end;
  
initialization
+
initialization
 
   {$I unit1.lrs}
 
   {$I unit1.lrs}
  
end.
+
end.</syntaxhighlight>
</delphi>
+
 
 +
&nbsp;&nbsp;&nbsp;El resultado es el documento XML siguiente:
  
The  result will be the XML file below:
+
<syntaxhighlight lang="xml"> <?xml version="1.0"?>
<xml>
+
<registrar>
<?xml version="1.0"?>
 
<register>
 
 
   <usuario id="001">
 
   <usuario id="001">
     <nome>Fernando</nome>
+
     <nombre>Fernando</nombre>
     <idade>32</idade>
+
     <edad>32</edad>
 
   </usuario>
 
   </usuario>
</register>
+
</registrar></syntaxhighlight>
</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
* Versión en castellano (español) [[User:Iskraelectrica | iskraelectrica (jldc)]] /diciembre de 2008.
+
* Versión inicial en castellano (español) [[User:Iskraelectrica | iskraelectrica (jldc)]] /diciembre de 2008.
 +
 
 +
&nbsp;&nbsp;&nbsp;Un ejemplo en el que no necesitamos referirnos a los elementos por su índice.
 +
<syntaxhighlight lang=pascal> procedure TForm1.Button2Click(Sender: TObject);
 +
var
 +
  Doc: TXMLDocument;
 +
  RootNode, ElementNode,ItemNode,TextNode: TDOMNode;
 +
  i: integer;
 +
begin
 +
  try
 +
    // Crear el documento
 +
    Doc := TXMLDocument.Create;
 +
    // Crear el nodo raiz
 +
    RootNode := Doc.CreateElement('Root');
 +
    Doc.Appendchild(RootNode);
 +
    RootNode:= Doc.DocumentElement;
 +
    // Crear los nodos
 +
    for i := 1 to 20 do
 +
      begin
 +
        ElementNode:=Doc.CreateElement('Element');
 +
        TDOMElement(ElementNode).SetAttribute('id', IntToStr(i));
 +
        ItemNode:=Doc.CreateElement('Item1');
 +
        TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
 +
        TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
 +
        TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i));
 +
        ItemNode.AppendChild(TextNode);
 +
        ElementNode.AppendChild(ItemNode);
 +
       
 +
        ItemNode:=Doc.CreateElement('Item2');
 +
        TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
 +
        TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
 +
        TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i));
 +
        ItemNode.AppendChild(TextNode);
 +
        ElementNode.AppendChild(ItemNode);
 +
       
 +
        RootNode.AppendChild(ElementNode);
 +
      end;
 +
      // Guardar el XML
 +
      WriteXMLFile(Doc,'TestXML_v2.xml');
 +
    finally
 +
    Doc.Free;
 +
  end;</syntaxhighlight>
 +
 
 +
&nbsp;&nbsp;&nbsp; Este es el documento XML generado:
 +
 
 +
<syntaxhighlight lang="xml"> <?xml version="1.0"?>
 +
<Root>
 +
  <Element id="1">
 +
  <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1>
 +
  <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2>
 +
  </Element>
 +
  <Element id="2">
 +
  <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1>
 +
  <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2>
 +
  </Element>
 +
  <Element id="3">
 +
  <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1>
 +
  <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2>
 +
  </Element>
 +
</Root></syntaxhighlight>
 +
--[[User:Mdalacu|Mdalacu]] 15:15, 18 Agosto 2011 (CEST)
 +
 
 +
=== Codificación ===
 +
 
 +
&nbsp;&nbsp;&nbsp;A partir de la revisión SVN 12582, XML reader es capaz de procesar los datos en cualquier codificación mediante el uso de decodificadores externos. Ver [[XML_Decoders/es|Decodificadores XML]] para más detalles.
  
=== Encoding ===
+
&nbsp;&nbsp;&nbsp;Según la norma XML puede haber un atributo de codificación en la primera línea del XML, pero no es obligatorio. La codificación actual es UTF-8(se presumes sin BOM - Marca de Orden de Byte) o UTF-16 (UTF-16 BOM).
  
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.
+
&nbsp;&nbsp;&nbsp;Desde la versión 0.9.26 de Lazarus (2.4 de FreePascal), existe una propiedad de codificación en TXMLDocument, pero se ignora. La función writeXMLFile utiliza siempre UTF-8 y no genera un atributo de codificación en la primera línea del documento XML.
  
== External Links ==
+
&nbsp;&nbsp;&nbsp;Las versiones FPC de la rama actual no escriben de manera explícita un atributo de codificación UTF-8, y este es necesario para algunos programas que no pueden manejar XML sin ella.
  
* [http://www.w3schools.com/xml/default.asp W3Schools] Xml Tutorial
+
== Ver también ==
 +
* [[XML Decoders/es|Decodificadores XML]]
 +
* [[Using INI Files/es|Usando archivos INI]]
  
* [http://www.thomas-zastrow.de/texte/fpcxml/index.php Thomas Zastrow article] FPC and XML
+
== Enlaces externos ==
  
[[Category:Free Component Library]]
+
* [http://www.w3schools.com/xml/default.asp Una tutoría sobre XML en W3Schools]
[[Category:Castellano]][[Category:Español]]
+
* [http://desarrollolibre.wordpress.com/2007/07/02/leer-archivos-xml-con-lazarus-i/ Leer un documento XML]
 +
* [http://www.thomas-zastrow.de/texte/fpcxml/index.php Un artículo de Thomas Zastrow sobre FPC y XML] [http://web.archive.org/web/20080802150722/http://www.thomas-zastrow.de/texte/fpcxml/index.php (Enlace alternativo)]
  
 
----
 
----
[[Multithreaded Application Tutorial]]
+
[[Multithreaded Application Tutorial/es|Tutoría de Aplicaciones Multihilo]]

Latest revision as of 02:42, 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)

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 la 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. Las unidades necesarias para compilar los códigos de los ejemplos (y para cualquier otro código con XML) son: DOM, XMLRead, XMLWrite, XMLCfg, XMLUtils, XMLStreaming. Aunque no todas son necesarias para todos los ejemplos.

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 version="1.0"?>
 <solicitud>
   <tipo_solicitud>PUT_FILE</tipo_solicitud>
   <usuario>123</usuario>
   <contrasenya>abc</contrasenya>
 </solicitud>

   Este ejemplo muestra la forma correcta y la incorrecta para obtener el valor textual de un nodo (no olvides añadir las unidades XMLRead and DOM en la sección uses):

 var
 NodoContra: TDOMNode;
  Doc:      TXMLDocument;
 begin
  try
   // leer archivo XMl desde disco
   ReadXMLFile(Doc, '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);
  finally
   // Y para terminar liberar la memoria que ocupa nuestro objeto Doc
   Doc.Free;
 end;
end;

   Ten en cuenta que ReadXMLFile (...) ignora todos los caracteres de espacios en blanco al analizar un documento. La sección espacios en blanco se describe cómo conservarlos.

Imprimir los nombres de los nodos y atributos

   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 'prueba.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>

   Y aquí el código Pascal para realizar el trabajo:

 var
   Documento : TXMLDocument;
   Hijo : TDOMNode;
   j: Integer;
 begin
  try
   ReadXMLFile(Documento, '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
         Memo.Lines.Add(format('%s %s (%s=%s; %s=%s)',
 	 [
 	  Item[j].NodeName,
 	  Item[j].FirstChild.NodeValue,
 	  Item[j].Attributes.Item[0].NodeName, // detalles del primer atributo
 	  Item[j].Attributes.Item[0].NodeValue,
 	  Item[j].Attributes.Item[1].NodeName, // detalles del segundo atributo
 	  Item[j].Attributes.Item[1].NodeValue
 	 ]));
     finally
       Free;
     end;
     Hijo := Hijo.NextSibling;
   end;
  finally
   Documento.Free;
  end;
 end;

   El resultado en Memo1 es:

 imagenesNodo: grafico.jpg
 Trozo: Trozocastillo.jpg1.swf (DestinoX=0; DestinoY=0)
 Trozo: PTrozocastillo.jpg2.swf (DestinoX=0; DestinoY=86)

(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.

 procedure TFormulario1.XML2Arbol(arbol: TTreeView; XMLDoc: TXMLDocument);
 var
  iNodo: TDOMNode;

  procedure ProcesaNodo(Nodo: TDOMNode; NodoArbol: TTreeNode);
  var
    cNodo: TDOMNode;
    s: string;
  begin
    if Nodo = nil then Exit; // Parar
    
    // Añadir nodo al árbol, si tiene atributos
     
      if Nodo.HasAttributes and (Nodo.Attributes.Length>0) then
         s:=Nodo.Attributes[0].NodeValue
      else
        s:=''; 
      TreeNode := tree.Items.AddChild(TreeNode, s);

    // 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;

   Otro ejemplo que muestra la estructura completa de XML con todos los valores de atributos::

 procedure XML2Tree(XMLDoc:TXMLDocument; TreeView:TTreeView);
 
  // función local que extrae como texto todos los atributos de los nodos 
  function GetNodeAttributesAsString(pNode: TDOMNode):string;
  var i: integer;
  begin
    Result:='';
    if pNode.HasAttributes then
      for i := 0 to pNode.Attributes.Length -1 do
        with pNode.Attributes[i] do
          Result := Result + format(' %s="%s"', [NodeName, NodeValue]);
 
    // Quita los epacios de principio y final
    Result:=Trim(Result);
  end;
 
  // Funcion recursiva que procesa un nodo y todos su nodos hijos
  procedure ParseXML(Node:TDOMNode; TreeNode: TTreeNode);
  begin
    // Salir del procedimiento si no hay nodos para procesar
    if Node = nil then Exit;
 
    // Añadir el nodo al arbol (TreeView)
    TreeNode := TreeView.Items.AddChild(TreeNode,Trim(Node.NodeName+' '+GetNodeAttributesAsString(Node)+ Node.NodeValue));
 
    // Procesar todos los nodos hijos
    Node := Node.FirstChild;
    while Node <> Nil do
    begin
      ParseXML(Node, TreeNode);
      Node := Node.NextSibling;
    end;
  end;
 
 begin
  TreeView.Items.Clear;
  ParseXML(XMLDoc.DocumentElement,nil);
 end;

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:

 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;

   CreateElement crea un nodo nuevo.

   CreateTextNode crea un valor par un nodo.

   CreateAttribute crea un atributo dentro de un nodo.

   CreateCDATA crea una sección CDATA: Los caracteres habituales de marca de XML cómo <> no se interpretan dentro de la sección CDATA. Ver artículo sobre CDATA en la Wikipedia

   Un método más adecuado para manipular atributos es utilizar el método TDOMElement.SetAttribute, que también se presenta como la propiedad predeterminada de TDOMElement:

 // Estos dos elementos son equivalentes
Element.SetAttribute('nombre', 'valor');
Element['nombre'] := 'valor';

   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.

 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;

Crear un TXMLDocument desde una cadena de caracteres

   Si MiCadenaXML contiene un documento XML, el código siguiente creará su DOM:

 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;

Validando un documento

   Desde marzo de 2007, la validación con DTD se ha añadido al analizador XML de la FCL. La validación verifica que la estructura lógica del documento se ajusta a las normas definidas en el DTD (Definición de Tipo de Documento) correspondiente.

   Este es un ejemplo de un documento XML con DTD:

 <?xml version='1.0'?>
 <!DOCTYPE raiz [
 <!ELEMENT raiz (child)+ >
 <!ELEMENT hijo (#PCDATA)>
 ]>
 <raiz>
   <hijo>Este es el primer hijo.</hijo>
   <hijo>Y este el segundo.</hijo>
 </raiz>

   Este DTD especifica que el elemento 'raiz' puede tener uno o más elementos 'hijo', y que estos, los elementos 'hijo', únicamente pueden contener caracteres de datos. Si el analizador informa si detecta alguna violación de estas reglas .

   Cargar un documento de esta forma es un poco más complicado. Supongamos que tenemos datos XML en un objeto TStream:

 procedure TMiObjeto.DOMdesdeFlujo(unFlujo: TStream);
 var
  Analizador : TDOMParser;
  Fuente : TXMLInputSource;
  Doc : TXMLDocument;
 begin
  try
   // creamos el objeto analizador
   Analizador := TDOMParser.Create;
   // y la fuente de entrada
   Fuente := TXMLInputSource.Create(unFlujo);
   // ahora validamos
   Analizador.Options.Validate := True;
   // asignamos un manejador de errores pra recibir las notificaciones
   Analizador.OnError := @ErrorHandler;
   // realizamos el trabajo
   Analizador.Parse(Fuente, Doc);
   // ...y hacemos limpieza (general)
  finally
   Fuente.Free;
   Analizador.Free;
  end;
 end;

 procedure TMiObjeto.ErrorHandler(Error: EXMLReadError);
 begin
  if Error.Severity = esError then  // únicamente nos interesan los errores de validación
    writeln(Error.Message);
 end;

Espacios en Blanco

   Si deseas conservar los espacios en blanco al principio de los textos de un nodo, el método anterior es la forma de cargar el documento XML. Los espacios en blanco iniciales son ignorados por defecto. Esta es la razón por la cual la función ReadXML (...) nunca devuelve los espacios en blanco en textos nodo.    Antes de llamar a Analizador.Parse(Fuente, Doc) inserta la línea

 Analizador.Options.PreserveWhitespace := True;

   Esto obliga a que el analizador devuelva todos los espacios en blanco. ¡Esto incluye también los caracteres de nueva línea que existen en un documento XML para que sea más fácil de leer!

Creando un documento XML

   A continuación se muestra el código completo para crear un documento XML y escribirlo en un archivo.

   (Esto está tomado de un tutorial del blog DeveLazarus)

   Recuerda poner en la cláusula uses las unidades DOM y XMLWrite

 unit Unidad1;

 {$mode objfpc}{$H+}

 interface

 uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
  DOM, XMLWrite;

 type
  { TForm1 }
  TForm1 = class(TForm)
    Boton1: TButton;
    Etiqueta1: TLabel;
    Etiqueta2: TLabel;
    procedure Boton1Click(Originador: TObject);
  private
    { declaraciones privadas}
  public
    { declaraciones publicas }
  end;
  
 var
  Form1: TForm1;
  
 implementation

 { TForm1 }

 procedure TForm1.Boton1Click(Originador : TObject);
 var
  xdoc: TXMLDocument;                                  // variable objeto documento XML
  NodoRaiz, NodoPadre, NodoHijo: TDOMNode;                    // variables a los nodos
 begin
  //crear el documento
  xdoc := TXMLDocument.create;

  NodoRaiz := xdoc.CreateElement('registrar');      //crear el nodo raíz
  Xdoc.Appendchild(NodoRaiz);                           // guardar nodo raíz

  NodoRaiz := xdoc.DocumentElement;   //crear el nodo padre
  NodoPadre := xdoc.CreateElement('usuario');
  TDOMElement(NodoPadre).SetAttribute('id', '001');       // crear los atributos del nodo padre
  NodoRaiz.Appendchild(NodoPadre);                          // guardar nodo padre

  NodoPadre := xdoc.CreateElement('nombre');                // crear el nodo hijo
  //TDOMElement(NodoPadre).SetAttribute('sexo', 'M');     // crear los atributos
  NodoHijo := xdoc.CreateTextNode('Fernando');         // insertar el valor del nodo
  NodoPadre.Appendchild(NodoHijo);                         // guardar nodo
  NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre);       // insertar el nodo hijo en el correspondiente nodo padre

  NodoPadre := xdoc.CreateElement('edad');               // crear el nodo hijo
  //TDOMElement(NodoPadre).SetAttribute('anyo', '1976');   // crear los atributos
  NodoHijo := xdoc.CreateTextNode('32');               // insertar el valor del nodo
  NodoPadre.Appendchild(NodoHijo);                         // guardar nodo
  NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre);       // insertar el nodo hijo en el correspondiente nodo padre

  writeXMLFile(xDoc,'prueba.xml');                     // escribir el XML
  Xdoc.free;                                          // liberar la memoria
 end;

 initialization
  {$I unit1.lrs}

 end.

   El resultado es el documento XML siguiente:

 <?xml version="1.0"?>
 <registrar>
  <usuario id="001">
    <nombre>Fernando</nombre>
    <edad>32</edad>
  </usuario>
 </registrar>

   Un ejemplo en el que no necesitamos referirnos a los elementos por su índice.

 procedure TForm1.Button2Click(Sender: TObject);
 var
   Doc: TXMLDocument;
   RootNode, ElementNode,ItemNode,TextNode: TDOMNode;
   i: integer;
 begin
   try
     // Crear el documento
     Doc := TXMLDocument.Create;
     // Crear el nodo raiz
     RootNode := Doc.CreateElement('Root');
     Doc.Appendchild(RootNode);
     RootNode:= Doc.DocumentElement;
     // Crear los nodos
     for i := 1 to 20 do
       begin
         ElementNode:=Doc.CreateElement('Element');
         TDOMElement(ElementNode).SetAttribute('id', IntToStr(i));
         ItemNode:=Doc.CreateElement('Item1');
         TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
         TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
         TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i));
         ItemNode.AppendChild(TextNode);
         ElementNode.AppendChild(ItemNode);
         
         ItemNode:=Doc.CreateElement('Item2');
         TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
         TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
         TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i));
         ItemNode.AppendChild(TextNode);
         ElementNode.AppendChild(ItemNode);
         
         RootNode.AppendChild(ElementNode);
       end;
       // Guardar el XML
       WriteXMLFile(Doc,'TestXML_v2.xml');
     finally
     Doc.Free;
   end;

    Este es el documento XML generado:

 <?xml version="1.0"?>
 <Root>
  <Element id="1">
   <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1>
   <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2>
  </Element>
  <Element id="2">
   <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1>
   <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2>
  </Element>
  <Element id="3">
   <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1>
   <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2>
  </Element>
 </Root>

--Mdalacu 15:15, 18 Agosto 2011 (CEST)

Codificación

   A partir de la revisión SVN 12582, XML reader es capaz de procesar los datos en cualquier codificación mediante el uso de decodificadores externos. Ver Decodificadores XML para más detalles.

   Según la norma XML puede haber un atributo de codificación en la primera línea del XML, pero no es obligatorio. La codificación actual es UTF-8(se presumes sin BOM - Marca de Orden de Byte) o UTF-16 (UTF-16 BOM).

   Desde la versión 0.9.26 de Lazarus (2.4 de FreePascal), existe una propiedad de codificación en TXMLDocument, pero se ignora. La función writeXMLFile utiliza siempre UTF-8 y no genera un atributo de codificación en la primera línea del documento XML.

   Las versiones FPC de la rama actual no escriben de manera explícita un atributo de codificación UTF-8, y este es necesario para algunos programas que no pueden manejar XML sin ella.

Ver también

Enlaces externos


Tutoría de Aplicaciones Multihilo