fabrice.marguerie@cogisoft.fr
Download version 04/27/1999
Currently, to access the content of an XML document, we can use parsers providing a DOM interface (Document Object Model).
Let's take a look at the following document (Books.xml):
<bookstore> <book genre="autobiography" count="15"> <title>The Autobiography of Benjamin Franklin</title> <author> <first_name>Benjamin</first_name> <last_name>Franklin</last_name> </author> <price>8.99</price> </book> <book genre="novel"> <title>The Confidence Man</title> <author> <first_name>Herman</first_name> <last_name>Melville</last_name> </author> <price>11.99</price> </book> <book genre="philosophy" count="2"> <title>The Gorgias</title> <author> <name>Plato</name> </author> <price>9.99</price> </book> </bookstore>
In case we use Microsoft's XML parser (msxml.dll version 2), we are given COM interfaces (IXMLDOMDocument, IXMLDOMNode, ...) to handle the XML document as a tree. These interfaces are not always adapted for some processings where a simpler system would be better. In some cases, we would like to be able to use calls like book.author.last_name to access the content of this document like fields of a structure.
We can achieve this through the mecanism that handles OLE Automation calls in Delphi.
To understand this mecanism you can take a look at the StringsAuto sample
that enables you to handle variables contained in a TStrings object as a structure's fields.
This way, if a TStrings object contains the following text:
Var1=abc Var2=def
we are able to access the value of Var1 with the call vStrings.Var1 where vStrings is a variant containing the TStrings object.
We will now see how to implement this functionality with Delphi 4 and Microsoft's XML parser (Internet Explorer 5 is required).
The code required is provided in the XMLAuto unit.
When a value is assigned to the Visible property of the Word object in the following example, we use an OLE Automation call handled by the VarDispInvoke procedure of Delphi's ComObj unit.
var Word: Variant; begin Word := CreateOleObject('Word.Application'); Word.Visible := True; end;
Delphi provides the VarDispProc variable that let us set up a new handler for OLE Automation calls. We will use this mecanism to handle calls against an XML document and its content.
var Document: Variant; begin Document := CoDOMDocument.Create; Document.load('Books.xml'); ShowMessage(Document.bookstore.book.author.last_name.text); end;
This kind of notation doesn't exclude calls to DOM:
ShowMessage(Document.bookstore.childNodes[1].author.last_name.text);
This kind of call needs the global variable EnableDOM to be set to True (default). This Way we can access DOM's methods or properties such as childNodes here.
We can also use the following call that references the second book:
ShowMessage(Document.bookstore.book[1].author.last_name.text);
To obtain a more compact code, it's possible to set the EnableDefaultProperty variable to True, implicating an implicit reference to the text property.
ShowMessage(Document.bookstore.book.author.last_name);
Of course modifications to the XML document are possible:
Document.bookstore.book.title.text := 'test write 1';
even if EnableDefaultProperty = True:
Document.bookstore.test1 := 'test write 3';
We are also able to dynamically create elements if they don't exist:
Document.bookstore.test1.text := 'test Write 2';
The global variable AutoCreateElement specifies if this mecanism of automatic creation is activated.
AutoCreateElement is compatible with EnableDefaultProperty:
Document.bookstore.test2 := 'test write 4'; Document.bookstore.test2[1] := 'test write 5';
In case EnableDOM = True, we can meet conflicts between
elements/attributes of the XML document and methods/properties of the XML DOM.
Assume an element element containing a text sub-element:
<element> <text>exemple de texte</text> <autre_sous_element>de conflit<autre_sous_element> </element>
The call element.text will always return "exemple de texte".
In some cases we want to access to the text "exemple de texte de conflit".
This is usually achieved with EnableDOM = True and the use of the text property of the DOM node.
Here, there is a conflict between the text element and the text property.
A workaround for this problem is to play on character's case. So, the call element.Text will return
"exemple de texte de conflit" if the DOM is enabled.
It is not possible to access elements or attributes containing symbols not supported by Delphi for identifiers (eg: last-name is invalid, last_name is valid). To access elements or attributes whose name includes a symbol, the DOM must be used.
How to access an attribute X where there is also an element X?
Elements are created automatically. How to create attributes? Use a new configuration flag?
It is highly recommended to use intermediate variables not to slowdown processings.
For example, to access information on a book, like this:
ShowMessage(Document.bookstore.book[1].author.last_name.text); ShowMessage(Document.bookstore.book[1].author.first_name.text);
it's better to use a Book variable of type Variant:
Book := Document.bookstore.book[1]; ShowMessage(Book.author.last_name.text); ShowMessage(Book.author.first_name.text);
The same kind of work can be done for datasets (TTable, TQuery, ...) to enable direct access to fields: tblCustomer.LastName := 'toto'.
For more information, to submit bugs, for suggestions, don't hesitate to contact me: fabrice.marguerie@cogisoft.fr
To get latest version, go to http://www.sophia-group.com/tech or http://www.sophia-group.com/downloads