XML Tutorial/es: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: XML Tutorial/es
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Introducción | |
| 2 | + | ||
| 3 | + | El Lenguaje de Marcas Extensible (XML) es recomendado por el [W3C](http://www.w3.org/) 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. | |
| 4 | + | ||
| 5 | + | 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. | |
| 6 | + | ||
| 7 | + | 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 [DOM XML 1.0](http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/). | |
| 8 | + | ||
| 9 | + | ## Ejemplos | |
| 10 | + | ||
| 11 | + | 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. | |
| 12 | + | ||
| 13 | + | ### Leyendo un nodo de texto | |
| 14 | + | ||
| 15 | + | Para programadores Delphi: | |
| 16 | + | ||
| 17 | + | 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. | |
| 18 | + | ||
| 19 | + | 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. | |
| 20 | + | ||
| 21 | + | Por ejemplo, veamos el siguiente XML: | |
| 22 | + | ||
| 23 | + | ``` xml | |
| 24 | + | <?xml version="1.0"?> | |
| 25 | + | <solicitud> | |
| 26 | + | <tipo_solicitud>PUT_FILE</tipo_solicitud> | |
| 27 | + | <usuario>123</usuario> | |
| 28 | + | <contrasenya>abc</contrasenya> | |
| 29 | + | </solicitud> | |
| 30 | + | ``` | |
| 31 | + | ||
| 32 | + | 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**): | |
| 33 | + | ||
| 34 | + | ``` pascal | |
| 35 | + | var | |
| 36 | + | NodoContra: TDOMNode; | |
| 37 | + | Doc: TXMLDocument; | |
| 38 | + | begin | |
| 39 | + | try | |
| 40 | + | // leer archivo XMl desde disco | |
| 41 | + | ReadXMLFile(Doc, 'prueba.xml'); | |
| 42 | + | // Extraer el nodo "contrasenya" | |
| 43 | + | NodoContra := Doc.DocumentElement.FindNode('contrasenya'); | |
| 44 | + | // Escribir el valor del nodo elegido | |
| 45 | + | WriteLn(NodoContra.NodeValue); // estará vacío | |
| 46 | + | // El texto del nodo es un nodo hijo en este momento | |
| 47 | + | WriteLn(NodoContra.FirstChild.NodeValue); // Presenta "abc", tal como deseábamos | |
| 48 | + | // alternativamente | |
| 49 | + | WriteLn(NodoContra.TextContent); | |
| 50 | + | finally | |
| 51 | + | // Y para terminar liberar la memoria que ocupa nuestro objeto Doc | |
| 52 | + | Doc.Free; | |
| 53 | + | end; | |
| 54 | + | end; | |
| 55 | + | ``` | |
| 56 | + | ||
| 57 | + | 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. | |
| 58 | + | ||
| 59 | + | ### Imprimir los nombres de los nodos y atributos | |
| 60 | + | ||
| 61 | + | 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. | |
| 62 | + | ||
| 63 | + | Este ejemplo muestra cómo mostrar los nombres de los nodos en un TMemo. | |
| 64 | + | ||
| 65 | + | Este es el XML, en el archivo 'prueba.xml': | |
| 66 | + | ||
| 67 | + | ``` xml | |
| 68 | + | <?xml version="1.0"?> | |
| 69 | + | <imagenes directorio="midir"> | |
| 70 | + | <imagenesNodo URL="grafico.jpg" rotulo=""> | |
| 71 | + | <Trozo DestinoX="0" DestinoY="0">Trozocastillo.jpg1.swf</Trozo> | |
| 72 | + | <Trozo DestinoX="0" DestinoY="86">Trozocastillo.jpg2.swf</Trozo> | |
| 73 | + | </imagenesNodo> | |
| 74 | + | </imagenes> | |
| 75 | + | ``` | |
| 76 | + | ||
| 77 | + | Y aquí el código Pascal para realizar el trabajo: | |
| 78 | + | ||
| 79 | + | ``` pascal | |
| 80 | + | var | |
| 81 | + | Documento : TXMLDocument; | |
| 82 | + | Hijo : TDOMNode; | |
| 83 | + | j: Integer; | |
| 84 | + | begin | |
| 85 | + | try | |
| 86 | + | ReadXMLFile(Documento, 'prueba.xml'); | |
| 87 | + | Memo.Lines.Clear; | |
| 88 | + | // usando las propiedades FirstChild y NextSibling | |
| 89 | + | Hijo := Documento.DocumentElement.FirstChild; | |
| 90 | + | while Assigned(Hijo) do | |
| 91 | + | begin | |
| 92 | + | Memo.Lines.Add(Hijo.NodeName + ' ' + Hijo.Attributes.Item[0].NodeValue); | |
| 93 | + | // using ChildNodes method | |
| 94 | + | with Hijo.ChildNodes do | |
| 95 | + | try | |
| 96 | + | for j := 0 to (Count - 1) do | |
| 97 | + | Memo.Lines.Add(format('%s %s (%s=%s; %s=%s)', | |
| 98 | + | [ | |
| 99 | + | Item[j].NodeName, | |
| 100 | + | Item[j].FirstChild.NodeValue, | |
| 101 | + | Item[j].Attributes.Item[0].NodeName, // detalles del primer atributo | |
| 102 | + | Item[j].Attributes.Item[0].NodeValue, | |
| 103 | + | Item[j].Attributes.Item[1].NodeName, // detalles del segundo atributo | |
| 104 | + | Item[j].Attributes.Item[1].NodeValue | |
| 105 | + | ])); | |
| 106 | + | finally | |
| 107 | + | Free; | |
| 108 | + | end; | |
| 109 | + | Hijo := Hijo.NextSibling; | |
| 110 | + | end; | |
| 111 | + | finally | |
| 112 | + | Documento.Free; | |
| 113 | + | end; | |
| 114 | + | end; | |
| 115 | + | ``` | |
| 116 | + | ||
| 117 | + | El resultado en Memo1 es: | |
| 118 | + | ||
| 119 | + | imagenesNodo: grafico.jpg | |
| 120 | + | Trozo: Trozocastillo.jpg1.swf (DestinoX=0; DestinoY=0) | |
| 121 | + | Trozo: PTrozocastillo.jpg2.swf (DestinoX=0; DestinoY=86) | |
| 122 | + | ||
| 123 | + | ### (re)Poblando un **TreeView** con XML | |
| 124 | + | ||
| 125 | + | 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. | |
| 126 | + | ||
| 127 | + | 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. | |
| 128 | + | ||
| 129 | + | ``` pascal | |
| 130 | + | procedure TFormulario1.XML2Arbol(arbol: TTreeView; XMLDoc: TXMLDocument); | |
| 131 | + | var | |
| 132 | + | iNodo: TDOMNode; | |
| 133 | + | ||
| 134 | + | procedure ProcesaNodo(Nodo: TDOMNode; NodoArbol: TTreeNode); | |
| 135 | + | var | |
| 136 | + | cNodo: TDOMNode; | |
| 137 | + | s: string; | |
| 138 | + | begin | |
| 139 | + | if Nodo = nil then Exit; // Parar | |
| 140 | + | ||
| 141 | + | // Añadir nodo al árbol, si tiene atributos | |
| 142 | + | ||
| 143 | + | if Nodo.HasAttributes and (Nodo.Attributes.Length>0) then | |
| 144 | + | s:=Nodo.Attributes[0].NodeValue | |
| 145 | + | else | |
| 146 | + | s:=''; | |
| 147 | + | TreeNode := tree.Items.AddChild(TreeNode, s); | |
| 148 | + | ||
| 149 | + | // ir al nodo hijo | |
| 150 | + | cNodo := Nodo.FirstChild; | |
| 151 | + | ||
| 152 | + | // Procesar todos los nodos hijos | |
| 153 | + | while cNodo <> nil do | |
| 154 | + | begin | |
| 155 | + | ProcesaNodo(cNodo, NodoArbol; | |
| 156 | + | cNodo := cNodo.NextSibling; | |
| 157 | + | end; | |
| 158 | + | end; | |
| 159 | + | ||
| 160 | + | begin | |
| 161 | + | iNodo := XMLDoc.DocumentElement.FirstChild; | |
| 162 | + | while iNodo <> nil do | |
| 163 | + | begin | |
| 164 | + | ProcesaNodo(iNodo, nil); // Recursivo | |
| 165 | + | iNodo := iNodo.NextSibling; | |
| 166 | + | end; | |
| 167 | + | end; | |
| 168 | + | ``` | |
| 169 | + | ||
| 170 | + | Otro ejemplo que muestra la estructura completa de XML con todos los valores de atributos:: | |
| 171 | + | ||
| 172 | + | ``` pascal | |
| 173 | + | procedure XML2Tree(XMLDoc:TXMLDocument; TreeView:TTreeView); | |
| 174 | + | ||
| 175 | + | // función local que extrae como texto todos los atributos de los nodos | |
| 176 | + | function GetNodeAttributesAsString(pNode: TDOMNode):string; | |
| 177 | + | var i: integer; | |
| 178 | + | begin | |
| 179 | + | Result:=''; | |
| 180 | + | if pNode.HasAttributes then | |
| 181 | + | for i := 0 to pNode.Attributes.Length -1 do | |
| 182 | + | with pNode.Attributes[i] do | |
| 183 | + | Result := Result + format(' %s="%s"', [NodeName, NodeValue]); | |
| 184 | + | ||
| 185 | + | // Quita los epacios de principio y final | |
| 186 | + | Result:=Trim(Result); | |
| 187 | + | end; | |
| 188 | + | ||
| 189 | + | // Funcion recursiva que procesa un nodo y todos su nodos hijos | |
| 190 | + | procedure ParseXML(Node:TDOMNode; TreeNode: TTreeNode); | |
| 191 | + | begin | |
| 192 | + | // Salir del procedimiento si no hay nodos para procesar | |
| 193 | + | if Node = nil then Exit; | |
| 194 | + | ||
| 195 | + | // Añadir el nodo al arbol (TreeView) | |
| 196 | + | TreeNode := TreeView.Items.AddChild(TreeNode,Trim(Node.NodeName+' '+GetNodeAttributesAsString(Node)+ Node.NodeValue)); | |
| 197 | + | ||
| 198 | + | // Procesar todos los nodos hijos | |
| 199 | + | Node := Node.FirstChild; | |
| 200 | + | while Node <> Nil do | |
| 201 | + | begin | |
| 202 | + | ParseXML(Node, TreeNode); | |
| 203 | + | Node := Node.NextSibling; | |
| 204 | + | end; | |
| 205 | + | end; | |
| 206 | + | ||
| 207 | + | begin | |
| 208 | + | TreeView.Items.Clear; | |
| 209 | + | ParseXML(XMLDoc.DocumentElement,nil); | |
| 210 | + | end; | |
| 211 | + | ``` | |
| 212 | + | ||
| 213 | + | ### Modificando un documento XML | |
| 214 | + | ||
| 215 | + | 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. | |
| 216 | + | ||
| 217 | + | 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. | |
| 218 | + | ||
| 219 | + | A continuación se presentan algunos métodos comunes de TDOMDocument: | |
| 220 | + | ||
| 221 | + | ``` pascal | |
| 222 | + | function CreateElement(const EtiquetaNombre: DOMString): TDOMElement; virtual; | |
| 223 | + | function CreateTextNode(const Datos: DOMString): TDOMText; | |
| 224 | + | function CreateCDATASection(const Datos: DOMString): TDOMCDATASection; virtual; | |
| 225 | + | function CreateAttribute(const nombre: DOMString): TDOMAttr; virtual; | |
| 226 | + | ``` | |
| 227 | + | ||
| 228 | + | `CreateElement` crea un nodo nuevo. | |
| 229 | + | ||
| 230 | + | `CreateTextNode` crea un valor par un nodo. | |
| 231 | + | ||
| 232 | + | `CreateAttribute` crea un atributo dentro de un nodo. | |
| 233 | + | ||
| 234 | + | `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](https://secure.wikimedia.org/wikipedia/en/wiki/CDATA) | |
| 235 | + | ||
| 236 | + | 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`: | |
| 237 | + | ||
| 238 | + | ``` pascal | |
| 239 | + | // Estos dos elementos son equivalentes | |
| 240 | + | Element.SetAttribute('nombre', 'valor'); | |
| 241 | + | Element['nombre'] := 'valor'; | |
| 242 | + | ``` | |
| 243 | + | ||
| 244 | + | 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|la función XML2Tree]]. | |
| 245 | + | ||
| 246 | + | ``` pascal | |
| 247 | + | procedure TForm1.actAnyadeNodoHijo(Remitente: TObject); | |
| 248 | + | var | |
| 249 | + | posicion: Integer; | |
| 250 | + | NeoNodo: TDomNode; | |
| 251 | + | begin | |
| 252 | + | {******************************************************************* | |
| 253 | + | * Hallar el elemento seleccionado | |
| 254 | + | *******************************************************************} | |
| 255 | + | if TreeView1.Selected = nil then Exit; | |
| 256 | + | ||
| 257 | + | if TreeView1.Selected.Level = 0 then | |
| 258 | + | begin | |
| 259 | + | posicion := TreeView1.Selected.Index; | |
| 260 | + | ||
| 261 | + | NeoNodo := XMLDoc.CreateElement('elemento'); | |
| 262 | + | TDOMElement(NovoNo).SetAttribute('nombre', 'Elemento'); | |
| 263 | + | TDOMElement(NovoNo).SetAttribute('archivo', 'Archivo'); | |
| 264 | + | with XMLDoc.DocumentElement.ChildNodes do | |
| 265 | + | begin | |
| 266 | + | Item[position].AppendChild(NeoNodo); | |
| 267 | + | Free; | |
| 268 | + | end; | |
| 269 | + | ||
| 270 | + | {******************************************************************* | |
| 271 | + | * Actualiza el árbol TreeView1 | |
| 272 | + | *******************************************************************} | |
| 273 | + | TreeView1.Items.Clear; | |
| 274 | + | XML2Tree(TreeView1, XMLDoc); | |
| 275 | + | end | |
| 276 | + | else if TreeView1.Selected.Level >= 1 then | |
| 277 | + | begin | |
| 278 | + | {******************************************************************* | |
| 279 | + | * Esta función únicamente trabaja en el primer nivel del árbol. | |
| 280 | + | * pero puede ser fácilmente modificada para que lo haga en cualesquiera niveles | |
| 281 | + | *******************************************************************} | |
| 282 | + | end; | |
| 283 | + | end; | |
| 284 | + | ``` | |
| 285 | + | ||
| 286 | + | ### Crear un TXMLDocument desde una cadena de caracteres | |
| 287 | + | ||
| 288 | + | Si MiCadenaXML contiene un documento XML, el código siguiente creará su DOM: | |
| 289 | + | ||
| 290 | + | ``` pascal | |
| 291 | + | Var | |
| 292 | + | Cadena: TStringStream; | |
| 293 | + | XML : TXMLDocument; | |
| 294 | + | ||
| 295 | + | begin | |
| 296 | + | Cadena:= TStringStream.Create(MiCadenaXML ); | |
| 297 | + | Try | |
| 298 | + | Cadena.Position:=0; | |
| 299 | + | XML:=Nil; | |
| 300 | + | ReadXMLFile(XML,Cadena); // El documento XML completo | |
| 301 | + | // Alternatively: | |
| 302 | + | ReadXMLFragment(UnNodoPadre,Cadena); // Lee únicamente un fragmento del XML | |
| 303 | + | Finally | |
| 304 | + | Cadena.Free; | |
| 305 | + | end; | |
| 306 | + | end; | |
| 307 | + | ``` | |
| 308 | + | ||
| 309 | + | ### Validando un documento | |
| 310 | + | ||
| 311 | + | 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. | |
| 312 | + | ||
| 313 | + | Este es un ejemplo de un documento XML con DTD: | |
| 314 | + | ||
| 315 | + | ``` xml | |
| 316 | + | <?xml version='1.0'?> | |
| 317 | + | <!DOCTYPE raiz [ | |
| 318 | + | <!ELEMENT raiz (child)+ > | |
| 319 | + | <!ELEMENT hijo (#PCDATA)> | |
| 320 | + | ]> | |
| 321 | + | <raiz> | |
| 322 | + | <hijo>Este es el primer hijo.</hijo> | |
| 323 | + | <hijo>Y este el segundo.</hijo> | |
| 324 | + | </raiz> | |
| 325 | + | ``` | |
| 326 | + | ||
| 327 | + | 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 . | |
| 328 | + | ||
| 329 | + | Cargar un documento de esta forma es un poco más complicado. Supongamos que tenemos datos XML en un objeto TStream: | |
| 330 | + | ||
| 331 | + | ``` pascal | |
| 332 | + | procedure TMiObjeto.DOMdesdeFlujo(unFlujo: TStream); | |
| 333 | + | var | |
| 334 | + | Analizador : TDOMParser; | |
| 335 | + | Fuente : TXMLInputSource; | |
| 336 | + | Doc : TXMLDocument; | |
| 337 | + | begin | |
| 338 | + | try | |
| 339 | + | // creamos el objeto analizador | |
| 340 | + | Analizador := TDOMParser.Create; | |
| 341 | + | // y la fuente de entrada | |
| 342 | + | Fuente := TXMLInputSource.Create(unFlujo); | |
| 343 | + | // ahora validamos | |
| 344 | + | Analizador.Options.Validate := True; | |
| 345 | + | // asignamos un manejador de errores pra recibir las notificaciones | |
| 346 | + | Analizador.OnError := @ErrorHandler; | |
| 347 | + | // realizamos el trabajo | |
| 348 | + | Analizador.Parse(Fuente, Doc); | |
| 349 | + | // ...y hacemos limpieza (general) | |
| 350 | + | finally | |
| 351 | + | Fuente.Free; | |
| 352 | + | Analizador.Free; | |
| 353 | + | end; | |
| 354 | + | end; | |
| 355 | + | ||
| 356 | + | procedure TMiObjeto.ErrorHandler(Error: EXMLReadError); | |
| 357 | + | begin | |
| 358 | + | if Error.Severity = esError then // únicamente nos interesan los errores de validación | |
| 359 | + | writeln(Error.Message); | |
| 360 | + | end; | |
| 361 | + | ``` | |
| 362 | + | ||
| 363 | + | ### Espacios en Blanco | |
| 364 | + | ||
| 365 | + | 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 | |
| 366 | + | ||
| 367 | + | ``` pascal | |
| 368 | + | Analizador.Options.PreserveWhitespace := True; | |
| 369 | + | ``` | |
| 370 | + | ||
| 371 | + | 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! | |
| 372 | + | ||
| 373 | + | ### Creando un documento XML | |
| 374 | + | ||
| 375 | + | A continuación se muestra el código completo para crear un documento XML y escribirlo en un archivo. | |
| 376 | + | ||
| 377 | + | (Esto está tomado de un tutorial del blog **DeveLazarus**) | |
| 378 | + | ||
| 379 | + | Recuerda poner en la cláusula uses las unidades DOM y XMLWrite | |
| 380 | + | ||
| 381 | + | ``` pascal | |
| 382 | + | unit Unidad1; | |
| 383 | + | ||
| 384 | + | {$mode objfpc}{$H+} | |
| 385 | + | ||
| 386 | + | interface | |
| 387 | + | ||
| 388 | + | uses | |
| 389 | + | Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, | |
| 390 | + | DOM, XMLWrite; | |
| 391 | + | ||
| 392 | + | type | |
| 393 | + | { TForm1 } | |
| 394 | + | TForm1 = class(TForm) | |
| 395 | + | Boton1: TButton; | |
| 396 | + | Etiqueta1: TLabel; | |
| 397 | + | Etiqueta2: TLabel; | |
| 398 | + | procedure Boton1Click(Originador: TObject); | |
| 399 | + | private | |
| 400 | + | { declaraciones privadas} | |
| 401 | + | public | |
| 402 | + | { declaraciones publicas } | |
| 403 | + | end; | |
| 404 | + | ||
| 405 | + | var | |
| 406 | + | Form1: TForm1; | |
| 407 | + | ||
| 408 | + | implementation | |
| 409 | + | ||
| 410 | + | { TForm1 } | |
| 411 | + | ||
| 412 | + | procedure TForm1.Boton1Click(Originador : TObject); | |
| 413 | + | var | |
| 414 | + | xdoc: TXMLDocument; // variable objeto documento XML | |
| 415 | + | NodoRaiz, NodoPadre, NodoHijo: TDOMNode; // variables a los nodos | |
| 416 | + | begin | |
| 417 | + | //crear el documento | |
| 418 | + | xdoc := TXMLDocument.create; | |
| 419 | + | ||
| 420 | + | NodoRaiz := xdoc.CreateElement('registrar'); //crear el nodo raíz | |
| 421 | + | Xdoc.Appendchild(NodoRaiz); // guardar nodo raíz | |
| 422 | + | ||
| 423 | + | NodoRaiz := xdoc.DocumentElement; //crear el nodo padre | |
| 424 | + | NodoPadre := xdoc.CreateElement('usuario'); | |
| 425 | + | TDOMElement(NodoPadre).SetAttribute('id', '001'); // crear los atributos del nodo padre | |
| 426 | + | NodoRaiz.Appendchild(NodoPadre); // guardar nodo padre | |
| 427 | + | ||
| 428 | + | NodoPadre := xdoc.CreateElement('nombre'); // crear el nodo hijo | |
| 429 | + | //TDOMElement(NodoPadre).SetAttribute('sexo', 'M'); // crear los atributos | |
| 430 | + | NodoHijo := xdoc.CreateTextNode('Fernando'); // insertar el valor del nodo | |
| 431 | + | NodoPadre.Appendchild(NodoHijo); // guardar nodo | |
| 432 | + | NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre); // insertar el nodo hijo en el correspondiente nodo padre | |
| 433 | + | ||
| 434 | + | NodoPadre := xdoc.CreateElement('edad'); // crear el nodo hijo | |
| 435 | + | //TDOMElement(NodoPadre).SetAttribute('anyo', '1976'); // crear los atributos | |
| 436 | + | NodoHijo := xdoc.CreateTextNode('32'); // insertar el valor del nodo | |
| 437 | + | NodoPadre.Appendchild(NodoHijo); // guardar nodo | |
| 438 | + | NodoRaiz.ChildNodes.Item[0].AppendChild(NodoPadre); // insertar el nodo hijo en el correspondiente nodo padre | |
| 439 | + | ||
| 440 | + | writeXMLFile(xDoc,'prueba.xml'); // escribir el XML | |
| 441 | + | Xdoc.free; // liberar la memoria | |
| 442 | + | end; | |
| 443 | + | ||
| 444 | + | initialization | |
| 445 | + | {$I unit1.lrs} | |
| 446 | + | ||
| 447 | + | end. | |
| 448 | + | ``` | |
| 449 | + | ||
| 450 | + | El resultado es el documento XML siguiente: | |
| 451 | + | ||
| 452 | + | ``` xml | |
| 453 | + | <?xml version="1.0"?> | |
| 454 | + | <registrar> | |
| 455 | + | <usuario id="001"> | |
| 456 | + | <nombre>Fernando</nombre> | |
| 457 | + | <edad>32</edad> | |
| 458 | + | </usuario> | |
| 459 | + | </registrar> | |
| 460 | + | ``` | |
| 461 | + | ||
| 462 | + | - Fernandosinesio 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com | |
| 463 | + | - Versión inicial en castellano (español) iskraelectrica (jldc) /diciembre de 2008. | |
| 464 | + | ||
| 465 | + | Un ejemplo en el que no necesitamos referirnos a los elementos por su índice. | |
| 466 | + | ||
| 467 | + | ``` pascal | |
| 468 | + | procedure TForm1.Button2Click(Sender: TObject); | |
| 469 | + | var | |
| 470 | + | Doc: TXMLDocument; | |
| 471 | + | RootNode, ElementNode,ItemNode,TextNode: TDOMNode; | |
| 472 | + | i: integer; | |
| 473 | + | begin | |
| 474 | + | try | |
| 475 | + | // Crear el documento | |
| 476 | + | Doc := TXMLDocument.Create; | |
| 477 | + | // Crear el nodo raiz | |
| 478 | + | RootNode := Doc.CreateElement('Root'); | |
| 479 | + | Doc.Appendchild(RootNode); | |
| 480 | + | RootNode:= Doc.DocumentElement; | |
| 481 | + | // Crear los nodos | |
| 482 | + | for i := 1 to 20 do | |
| 483 | + | begin | |
| 484 | + | ElementNode:=Doc.CreateElement('Element'); | |
| 485 | + | TDOMElement(ElementNode).SetAttribute('id', IntToStr(i)); | |
| 486 | + | ItemNode:=Doc.CreateElement('Item1'); | |
| 487 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 488 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 489 | + | TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i)); | |
| 490 | + | ItemNode.AppendChild(TextNode); | |
| 491 | + | ElementNode.AppendChild(ItemNode); | |
| 492 | + | ||
| 493 | + | ItemNode:=Doc.CreateElement('Item2'); | |
| 494 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 495 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 496 | + | TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i)); | |
| 497 | + | ItemNode.AppendChild(TextNode); | |
| 498 | + | ElementNode.AppendChild(ItemNode); | |
| 499 | + | ||
| 500 | + | RootNode.AppendChild(ElementNode); | |
| 501 | + | end; | |
| 502 | + | // Guardar el XML | |
| 503 | + | WriteXMLFile(Doc,'TestXML_v2.xml'); | |
| 504 | + | finally | |
| 505 | + | Doc.Free; | |
| 506 | + | end; | |
| 507 | + | ``` | |
| 508 | + | ||
| 509 | + | Este es el documento XML generado: | |
| 510 | + | ||
| 511 | + | ``` xml | |
| 512 | + | <?xml version="1.0"?> | |
| 513 | + | <Root> | |
| 514 | + | <Element id="1"> | |
| 515 | + | <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1> | |
| 516 | + | <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2> | |
| 517 | + | </Element> | |
| 518 | + | <Element id="2"> | |
| 519 | + | <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1> | |
| 520 | + | <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2> | |
| 521 | + | </Element> | |
| 522 | + | <Element id="3"> | |
| 523 | + | <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1> | |
| 524 | + | <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2> | |
| 525 | + | </Element> | |
| 526 | + | </Root> | |
| 527 | + | ``` | |
| 528 | + | ||
| 529 | + | --Mdalacu 15:15, 18 Agosto 2011 (CEST) | |
| 530 | + | ||
| 531 | + | ### Codificación | |
| 532 | + | ||
| 533 | + | 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. | |
| 534 | + | ||
| 535 | + | 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). | |
| 536 | + | ||
| 537 | + | 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. | |
| 538 | + | ||
| 539 | + | 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. | |
| 540 | + | ||
| 541 | + | ## Ver también | |
| 542 | + | ||
| 543 | + | - [[XML Decoders/es|Decodificadores XML]] | |
| 544 | + | - [[Using INI Files/es|Usando archivos INI]] | |
| 545 | + | ||
| 546 | + | ## Enlaces externos | |
| 547 | + | ||
| 548 | + | - [Una tutoría sobre XML en W3Schools](http://www.w3schools.com/xml/default.asp) | |
| 549 | + | - [Leer un documento XML](http://desarrollolibre.wordpress.com/2007/07/02/leer-archivos-xml-con-lazarus-i/) | |
| 550 | + | - [Un artículo de Thomas Zastrow sobre FPC y XML](http://www.thomas-zastrow.de/texte/fpcxml/index.php) [(Enlace alternativo)](http://web.archive.org/web/20080802150722/http://www.thomas-zastrow.de/texte/fpcxml/index.php) | |
| 551 | + | ||
| 552 | + | ------------------------------------------------------------------------ | |
| 553 | + | ||
| 554 | + | [[Multithreaded Application Tutorial/es|Tutoría de Aplicaciones Multihilo]] | |
| 555 | + | ||
| 556 | + | --- | |
| 557 | + | *From the Free Pascal wiki, page "XML Tutorial/es", as it stood on 2020-03-02 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
