Mega Code Archive

 
Categories / Delphi / XML
 

Delphi XML Binding Wizard Tutorial

Title: Delphi XML Binding Wizard Tutorial Question: The Delphi XML Binding Wizard requires some understanding to be used. I'll show you Answer: Delphi XML Binding Wizard Tutorial The Delphi XML Binding Wizard requires some understanding to be used. I'll show you Introduction The XML binding wizard lets developers using XML files avoid all the mess related to xml node management. This is obtained by abstracting the xml document to a set of interfaces defining the final values, rather than nodes. How the file is handled at the binding level Each xml file is composed of a root node and several child nodes. This means that the root node code will be an interface inheriting from XMLDocument. While this may seem obvious to experienced users, beginners have to consider what this means, because it implies several other things. First of all, it means that you can access the underlying original XML document if you have to perform some operations, such as an XPath selection. Second, it implies that - if you really want to - you can reuse code relying on the IXMLDocument interface for your current binding. This is useful if you have, for example, routines to bind an XML document to a treeview (which is quite common). Third, it means that it's very easy to generate a brand new XML file using the binding and then expose the generated XML, just use the XML property of type TStrings. Child nodes are another consideration. The wizard can distinguish between composite and simple nodes. Thus, if you have a "items" node with several "item" nested nodes, the wizard will be smart enough to recognize the pattern and accomodate your generated code accordingly. Child nodes can derive from any IXMLNode or inherited interface according to the type of node, except IXMLDocument(which is reserved, as mentioned above, to the root node). You will notice that there's no function whatsoever to create a child node unless it is a composite node. This is what the wizard is all about: you set interface properties and Delphi will take care of creating the nodes. If, however, there's a composite node, there's then going to be an ADD method allowing you to set the child nodes. This method is a function returning the most convenient interface, like in this example: var MyChildNode : IMyChildNode; begin MyChildNode := MyParentNode.Add; // Set MyChildNode properties here, Delphi behind the scenes will create the nodes. end; When to use the wizard The wizard can be used in most occasions. It's very handy especially for those XML files that can get slightly convoluted or that are not under our control. The best feature of the wizard is that, if a new, compatible XML schema or file is sent to you, you can simply re-generate the source and you're done. Alternatives to the wizard The main, supported, alternative to the wizard is the use of a client dataset. While it's not exactly an XML file in its own merit (i.e. the CDS really is a database), it can be saved to XML and can also be transformed (using the XML mapper) into a custom XML file. Thus, you can prototype your data model using a client dataset, transform it to an XML file, feed it to the wizard, and voil. What to feed to the wizard The binding wizard can be fed with several different xml file types: * Data files (with .xml extension) * Schema files (with .xsd extension) * XTR files (very rare, just don't care) You'll likely feed the wizard with XML files, less likely (but still very possible) with schema ones. A sample file import Let's see a sample XML file. with text in it Start the wizard and import it. You will obtain these interfaces: { IXMLRootelementType } IXMLRootelementType = interface(IXMLNode) ['{875F00D6-2822-4DC7-B4F7-6178F9456EC8}'] { Property Accessors } function Get_Childnodes: IXMLChildnodesType; function Get_Anotherchildnode: WideString; procedure Set_Anotherchildnode(Value: WideString); { Methods & Properties } property Childnodes: IXMLChildnodesType read Get_Childnodes; property Anotherchildnode: WideString read Get_Anotherchildnode write Set_Anotherchildnode; end; { IXMLChildnodesType } IXMLChildnodesType = interface(IXMLNodeCollection) ['{F26112C9-A8F2-4852-8EE2-86E50702015B}'] { Property Accessors } function Get_Attr1: Integer; function Get_Childnode(Index: Integer): IXMLChildnodeType; procedure Set_Attr1(Value: Integer); { Methods & Properties } function Add: IXMLChildnodeType; function Insert(const Index: Integer): IXMLChildnodeType; property Attr1: Integer read Get_Attr1 write Set_Attr1; property Childnode[Index: Integer]: IXMLChildnodeType read Get_Childnode; default; end; { IXMLChildnodeType } IXMLChildnodeType = interface(IXMLNode) ['{E8DDAFCC-84BC-4067-808F-0D5DAF829436}'] { Property Accessors } function Get_Attr2: Integer; function Get_Attr3: Integer; procedure Set_Attr2(Value: Integer); procedure Set_Attr3(Value: Integer); { Methods & Properties } property Attr2: Integer read Get_Attr2 write Set_Attr2; property Attr3: Integer read Get_Attr3 write Set_Attr3; end; Now, if we look at this source code, well see that, for instance, AnotherChildNode is a simple string, whereas ChildNodes has the famous .ADD method. How do you use those interfaces? Its pretty simple: procedure NewXMLFile( out RootNode : IXMLRootelementType;AnotherChildElement : String ); begin RootNode := NewRootelement; RootNode.AnotherChildElement := AnotherChildElement; end; procedure AddChildElement( RootNode: IXMLRootElementType;Attr2, Attr3 : String ); var ChildNode : IXMLChildNodeType; begin ChildNode := RootNode.ChildNodes.Add; ChildNode.Attr2 := Attr2; ChildNode.Attr3 := Attr3; end; Lets now have a look at how the NewRootElement function is implemented: function Newrootelement: IXMLRootelementType; begin Result := NewXMLDocument.GetDocBinding('rootelement', TXMLRootelementType) as IXMLRootelementType; end; The NewXMLDocument function is declared in XMLDoc.pas and creates an interfaced TXMLDocument instance. When not to use the XML binding wizard? As you probably noticed, the XML binding requires a DOM-oriented parser. That is, you need to be loading and keeping all of your document in memory. Thus, you shouldnt be using it when you dont need all of your document in memory. An example of this may be, for instance, some kind of tag based generator. Consider this XML file: In this case, you simply need to parse each tag, you dont need a DOM, thus you dont need a bound XML. Yeah, you can still choose to use one, but this is not required. Another case is when you need XPath, then you got to use the native IXMLDocument interface. But thats for another tutorial, really. Conclusions As you can see, XML binding is quite easy to use and powerful. Im sure youll like it quite a bit, actually, when youre going to use it. Now you know the basics to use it proficiently, just go and bind your files!