DOMinando XML El motivo del presente articulo es el de servir como mini tutorial para mostrar como generar un XML dinamicamente en Delphi.. No pretende abarcar el tema de tratamiento XML en este lenguaje en profundidad sino de servir como una guia rapida y un punto de partida para cualquier persona que desee generar sus propios archivos en este formato. El código fuente mostrado aquí fue escrito con Delphi 7. Manos al XML Trataremos de generar un XML muy simple con la información que se muestra a continuación: <libros> <libro> <titulo>El Sastre de Panamá </titulo> <autor>John Le Carre </autor> </libro> <libro> <titulo> La piel del tambor</titulo> <autor> Arturo Perez Reverte</autor> </libro> </libros> Para generarlo deberemos haremos uso de las units xmlDoc y xmlIntf que vienen con Delphi y nos proporcionan un conjunto de clases e interfaces para la manipulacion y generación de documentos xml. La clase principal se llama TXMLDocument, está definida en la unit xmlDoc e implementa una interfaz llamada IXMLDocument cuya definición se encuentra en la unit xmlIntf. Para manipular los tags o elementos del XML tenemos la clase TXMLNode que implementa IXMLNode. Por útimo mencionamos la interfaces IXMLNodeList y IXMLNodeCollection para manejar un conjunto de nodos. En este caso nos manejaremos siempre teniendo referencias de tipo interfaz.. Para entender el mecanismo de generación de un documento XML debemos verlo como un árbol donde cada elemento se corresponde a un Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 23 de Febrero del 2005 1 nodo(IXMLNode). En el caso del documento XML mostrado anteriormente podriamos inferir su estructura como la siguiente Esquema del XML en Arbol Para no tentar a la impaciencia mostremos como sería el código fuente que genera ese documento. Vamos a iniciar una aplicación nueva y vamos a arrastrar un boton sobre el formulario. Luego le programaremos la generacion del xml asociado al click del boton. El resultado final se vera similar a : unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, xmlDoc, xmlIntf; Type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var ADoc : IXMLDocument; ARootNode : IXMLNode; ANode : IXMLNode; begin ADoc := TXMLDocument.Create(nil); Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 23 de Febrero del 2005 2 ADoc.Active := true; ADoc.Options := ADoc.Options + [doNodeAutoIndent]; ARootNode := ADoc.AddChild('Libros'); //Agrego el primer libro ANode := ARootNode.AddChild('Libro'); ANode.AddChild('Titulo').NodeValue := 'El Sastre de Panama'; ANode.AddChild('Autor').NodeValue := 'John Le Carre'; //Agrego el segundo libro ANode := ARootNode.AddChild('Libro'); ANode.AddChild('Titulo').NodeValue := 'La piel del tambor'; ANode.AddChild('Autor').NodeValue := 'Arturo Perez Reverte'; //Salvo el archivo ADoc.SaveToFile(SysUtils.ExtractFilePath(Application.ExeName)+'Libros.xml'); ADoc.Active := False; ADoc := nil; end; end. Ahora solo basta compilar y ejecutar la aplicación, apretar el boton y luego abrir el documento Libros.xml donde voilá, tenemos el documento tal cual fue presentado. Metiendonos dentro de la interfaz Para el que desee profundizar un poco mas en la generacion, lectura y manejo de XML vamos a incluir un bosquejo de las interfaces IXMLDocument e IXMLNode para el que desee profundizar sobre el tema. IXMLDocument = interface(IInterface) function AddChild(const TagName: DOMString): IXMLNode; function AddChild(const TagName, NamespaceURI: DOMString): IXMLNode; function CreateElement(const TagOrData, NamespaceURI: DOMString): IXMLNode; function CreateNode(const NameOrData: DOMString): IXMLNode; function GeneratePrefix(const Node: IXMLNode): DOMString; function GetDocBinding(const TagName: DOMString; NodeClass: TClass): IXMLNode; function IsEmptyDoc: Boolean; procedure LoadFromFile(const AFileName: DOMString); procedure LoadFromStream(const Stream: TStream); procedure LoadFromXML(const XML: string); procedure LoadFromXML(const XML: DOMString); procedure Refresh; procedure RegisterDocBinding(const TagName: DOMString;DocNodeClass: TClass); procedure Resync; procedure SaveToFile(const AFileName: DOMString); procedure SaveToStream(const Stream: TStream); procedure SaveToXML(var XML: DOMString); overload; procedure SaveToXML(var XML: string); overload; procedure SetOnAsyncLoad(const Value: TAsyncEventHandler); { Properties } Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 23 de Febrero del 2005 3 property property property property property property property property property property property property property property property property end; Active: Boolean; AsyncLoadState: Integer; ChildNodes: IXMLNodeList DocumentElement: IXMLNode DOMDocument: IDOMDocument Encoding: DOMString FileName: DOMString Modified: Boolean; Node: IXMLNode; NodeIndentStr: DOMString; Options: TXMLDocOptions; ParseOptions: TParseOptions; SchemaRef: DOMString; StandAlone: DOMString; Version: DOMString; XML: TStrings; Para manejar cada nodo... IXMLNode = interface ['{395950C0-7E5D-11D4-83DA-00C04F60B2DD}'] { Methods } function AddChild(const TagName: DOMString; Index: Integer = -1): IXMLNode; function AddChild(const TagName, NamespaceURI: DOMString): IXMLNode; function CloneNode(Deep: Boolean): IXMLNode; procedure DeclareNamespace(const Prefix, URI: DOMString); function FindNamespaceURI(const TagOrPrefix: DOMString): DOMString; function FindNamespaceDecl(const NamespaceURI: DOMString): IXMLNode; function GetAttributeNS(const AttrName, NamespaceURI: DOMString): OleVariant; function HasAttribute(const Name: DOMString): Boolean; function HasAttribute(const Name, NamespaceURI: DOMString): Boolean; function NextSibling: IXMLNode; function PreviousSibling: IXMLNode; procedure Resync; procedure SetAttributeNS(const AttrName, NsURI: DOMString; Value: OleVariant); procedure TransformNode(const stylesheet: IXMLNode; var output: WideString); procedure TransformNode(const stylesheet: IXMLNode; const output: IXMLDocument); { Properties } property Attributes[const AttrName: DOMString]: OleVariant; property AttributeNodes: IXMLNodeList; property ChildNodes: IXMLNodeList; property ChildValues[const IndexOrName: OleVariant]: OleVariant; property Collection: IXMLNodeCollection; property DOMNode: IDOMNode; property OwnerDocument: IXMLDocument; property HasChildNodes: Boolean; property IsTextElement: Boolean; property LocalName: DOMString; property NamespaceURI: DOMString; property NodeName: DOMstring; property NodeType: TNodeType; property NodeValue: OleVariant; property ParentNode: IXMLNode; property Prefix: DOMString; property ReadOnly: Boolean; property Text: DOMString; property XML: DOMString; end; Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 23 de Febrero del 2005 4 DOM-inando el XML Es común que cuando se habla de XML oir las siglas DOM (Document Object Model). Ellas hacen referencia a una interfaz (o conjunto de interfaces) estandar para manejar XML. Su especificación es parte de una recomencacion de W3C y por lo tanto se pueden usar en varios lenguajes sin temor a que cambien en el futuro. Pero dejaremos el tema de DOM para articulos posteriores. Se puede visitar (http://www.w3.org/DOM/) para la especificacion de DOM. Las clases e interfaces que utilizamos que internamente utilizan una implementación de las interfaces DOM. Es decir, cada vez que llamamos un metodo de la clase que nos provee delphi, la implementación del mismo simplemente lo traduce en la invocacion de uno o varios metodos definidos por la interfaz DOM. Funciona como un Adaptador. De hecho si desearamos trabajar directamente con la interfaz DOM, ya sea porque tenemos experiencia con la misma por haberla usado en otro lenguaje como Javascript podemos hacerlo sin problema. Notese que dentro de la interfaz IXMLDocument tenemos una propiedad llamada DOMDocument que nos devuelve un IDOMDocument. Esta última es una interfaz que cumple la especificación de DOM. Analogamente podemos acceder a un IDOMNode a travez de la propiedad DOMNode definida en la interfaz IXMLDOM. DOM define la interfaz pero nada dice de la implementación. Delphi trae una por defecto pero podemos utilizar una propia en reemplazo de la que viene por defecto con unos pocos cambios. En futuros articulos exploraremos el tema de XML más en profundidad. Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 23 de Febrero del 2005 5