DOMinando XML - Esteban Calabria

Anuncio
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
Descargar