|Delphi Clinic||C++Builder Gate||Training & Consultancy||Delphi Notes Weblog||Dr.Bob's Webshop|
Delphi 6 XML Document Programming
Delphi 6 contains a lot of new and enhanced XML support. In previous versions of Delphi, XML was already used for example as format for the MIDAS data packets to and from XMLBroker components (as well as in the local file formats for ClientDataSet and ADODataSet components).
With Delphi 6, new XML features have been added in the form of XML document programming, XML Data Binding Wizard, XML Mapper and BizSnap (SOAP/XML Web Services). This is the first in a series of three articles about Delphi 6 XML support. This time starting off with XML Document Programming in Delphi 6.
Ever since it was born, a few years ago, XML was dubbed the Esperanto of e-business. Especially in the B2B (business-2-business) electronic commerce area. The reason for this is that an XML is basically a simple yet structured ASCII text file that everyone and everything can read. Not unlike HTML, which currently is the standard format for webpages. The difference between XML and HTML is the fact that for HTML a pre-defined set of syntax rules exists. An XML document needs to follow the general XML syntax rules, but the exact keywords (tags) that can be used in an XML document are up to the author of the document, and optionally specified in something called the DTD (Document Type Definition) or more recently an XML Schema. Together with a DTD or Schema, an XML document is said to be a self-describing document, which is handy when it comes to error correcting and data integrity.
XML is a way to give structure to data and information that can be passed between one application to another (including inter-application communication between multiple tiers, like Delphi offers). As such, it offers a standard format, independent of the communication protocol being used. This is also one of the reasons why XML will play an important role in Electronic Commerce EDI (Electronic Data Interchange) and B2B applications and situations. The fact that a DTD (or XML Schema) can be used to "define" (and check) the XML document itself means that - theoretically - everyone can talk to everyone and everything as long as proper XML/DTD/Schema combination is used. More and more often we'll have to integrate existing systems, and XML may be the "language" with which to make sure the systems can talk to each other (and understand each other).
This article will not be about XML as used in EDI or B2B, but it will start a series of three articles on XML documents and programming XML documents with some of the new XML features of Delphi 6.
XML document programming
Delphi 6 contains support for a DOM parser with which we are enabled to read (and interpret!) and edit any XML document. Even it a DTD or XML Schema is missing, as we'll see in this article. For the XML examples in this article, I've created a little XML file (using notepad). The XML file is a regular XML document that contains information about my (Dutch) Delphi 6 Clinics, which contains the following information:
<?xml version="1.0" standalone="yes" ?> <Clinics> <Clinic No="2002-1"> <Title>dbExpress and DataSnap</Title> <Date>2002/01/10</Date> <Topics> </Topics> </Clinic> <Clinic No="2002-2"> <Title>WebBroker/InternetExpress and WebSnap</Title> <Date>2002/01/31</Date> <Topics> </Topics> </Clinic> <Clinic No="2002-3"> <Title>WebSnap and Adapters</Title> <Date>2002/02/21</Date> <Topics> </Topics> </Clinic> <Clinic No="2002-4"> <Title>BizSnap and WebServices</Title> <Date>2002/03/14</Date> <Topics> </Topics> </Clinic> <Clinic No="2002-5"> <Title>WebSnap and BizSnap</Title> <Date>2002/04/04</Date> <Topics> </Topics> </Clinic> </Clinics>This XML document will be used by a number of the XML examples in this article series (this time and the two following articles about XML Data Binding and the XML Mapper).
For the first topic of XML Document programming, we need to use an TXMLDocument component (from the Internet tab of the Delphi 6 Component Palette), so drop one on your form or data module. The XMLDocument component has a number of properties that are worthy some attention. Obviously, the Active property can be used to "open" the XML document, but we're not quite ready, yet. The DOMVendor property specifies the XML DOM parser that we want to use. On my machine, it's set to MSXML, but you can plug any other DOMVendor (basically any component that implements the IDOMImplementation interface). Before you can use any other DOMVendor, however, it must be registered. The global variable DOMVendors contains a list of registered DOMVendor values (so third-party DOMVendors can be registered and added to this list, giving you other options to use for the DOMVendor property of the TXMLDocument component).
The third property is the FileName, which should point to the XML document (in our case clinics.xml). If the XML document is not stored in a filename, but rather received by some transport, then you can also assign the XML value to the XML property itself. The latter is especially useful in EDI and B2B situations (where you don't need to store the incoming XML document in an actual file).
The NodeIndentStr property specifies how the (child) nodes in the resulting XML document are indented. By default, the indentation is two spaces, but you can select anything from one to eight spaces or a tab. This property is only used if the Options property includes the doNodeAutoIndent value (which is off by default). The Options property also contains flags for NodeAutoCreate, AttrNull, AutoPrefix, NamespaceDecl and AutoSave (to save the XML document inside the FileName when the XMLDocument component is deactivated). I think autosave is a nice feature, so although it's set to False by default, I'll turn it to True for today's example.
Apart from regular Options, the XMLDocument component also contains special ParseOptions, such as ResolveExternals, ValidateOnParse, PreserveWhiteSpace and AsyncLoad (most of which are self-explanatory).
The final property of the XMLDocument component is the XML property itself. You can assign any XML string directly to this property, or click on the ellipsis next to the property (in the Object Inspector) to start the Strings Editor and type a few lines of XML. Like I said before, this property is most useful in a multi-tier B2B approach where some XML string (representing an XML document from another application) is received, and we need to process it or "program" with the contents.
XML Document Programming
We only made a few changes (the FileName property was set to clinics.xml and the doAutoSave flag of the Options property was set to True). Now, set the Active property to True, and once you have an active TXMLDocument object, you can walk the hierarchy of nodes, reading values, editing them, etc.
We can now access individual nodes (of type IXMLNode) in the XMLDocument, and from each node recursively access the individual ChildNotes. For example, we can drop a button that would extract the information from the first Node (the first Clinic) and then the Title, Date and Topics ChildNode information from that Node, and put it all inside a Memo's Lines:
procedure TForm1.Button1Click(Sender: TObject); var Clinic: IXMLNode; begin Clinic := XMLDocument1.DocumentElement.ChildNodes; Memo1.Lines.Clear; Memo1.Lines.Add(Clinic.ChildNodes['Title'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Date'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Topics'].Text) end;We can also navigate through the ChildNodes (by just increasing the index). Just add a variable called "current" to the Form that maintains the current ChildeNode index. A "Next" button would only need to increase the value of current and present the current value of the ChildNode (note that the try-except clause is needed in case we move beyond the end of the XML document):
procedure TForm1.Button2Click(Sender: TObject); var Clinic: IXMLNode; begin Inc(current); try Clinic := XMLDocument1.DocumentElement.ChildNodes[current]; Memo1.Lines.Clear; Memo1.Lines.Add(Clinic.ChildNodes['Title'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Date'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Topics'].Text); except on E: Exception do Memo1.Lines.Add(E.Message) end end;Apart from moving from one node to another, we can also edit the content of individual ChildNodes, by simple assigning a new value to them, as follows (this is the code for the First button again, this time assigning the current variable as well as adding a prefix of "Hot: " to the first Clinic title text):
procedure TForm1.Button1Click(Sender: TObject); var Clinic: IXMLNode; begin current := 0; Clinic := XMLDocument1.DocumentElement.ChildNodes[current]; Memo1.Lines.Clear; Clinic.ChildNodes['Title'].Text := 'HOT: ' + Clinic.ChildNodes['Title'].Text; Memo1.Lines.Add(Clinic.ChildNodes['Title'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Date'].Text); Memo1.Lines.Add(Clinic.ChildNodes['Topics'].Text); end;And we can even add or delete child nodes. To add a child node, and fill it with default values, you can write the following code:
procedure TForm1.Button1Click(Sender: TObject); var Clinic: IXMLNode; begin Clinic := XMLDocument1.DocumentElement.AddChild('Clinic'); Clinic.ChildNodes['Title'].Text := 'Title'; Clinic.ChildNodes['Date'].Text := 'Date'; Clinic.ChildNodes['Topics'].Text := 'Topics'; end;Remember that we set the AutoSave flag of the Options property to true, so any changes will be saved automatically when we deactivate the XMLDocument component (or close the application). If you want to explicitly save the XMLDocument, you can always call XMLDocument1.SaveToFile. This method has a default argument with the filename, which is not needed if you're already using the FileName property.
Next: XML Data Binding
The XMLDocument offers us ways to work with and edit the contents of an XML Document. However, we can only work with unnamed ChildNodes (of type IXMLNode), and we have to know the names of the attributes (child nodes) ourselves (although you there is a FindAttribute method available that you can use).
And although the code presented in this article will work just fine for relative simple or small XML documents, Delphi wouldn't be Delphi if the support could be made a little bit more intuitive. Using context-sensitive structure information from the XML document itself. This is possible with a somewhat more advanced new Delphi 6 feature called XML Data Binding, which we'll see in the next article.
For more recent information on Delphi for Win32 XML Programming, check out my Delphi 2010 XML, SOAP & Web Services courseware manual.