XML Data Binding

   

In the previous section we worked with the _di_IXMLDocument interface as implemented by the TXMLDocument component. And, although it's useful, the downside is that is doesn't offer us semantic support for the XML document. One typing mistake causes you to not find the value of a child node, but accidentally add a new child node to the tree.

Fortunately, C++Builder 6 also contains a way to perform XML Data Binding, whereby an XML Document is used to generate specific interfaces and C++ class definitions and implementations that will help us make fewer mistakes by offering named methods as well as Code Insight support. You'll get the idea when we look at how it works.

The work is done by the XML Data Binding Wizard, which can be found in the Object Repository after you do File, New, Other (see Figure 13.3).

Figure 13.3. XML Data Binding icon in Object Repository.

graphics/13fig03.jpg

The XML Data Binding Wizard has three pages, although the first page is optional (as I'll explain in a moment). The fist page is used to specify the name of the XML document, which is shown in Figure 13.4. Note that apart from an actual XML data document, we can also specify an XML schema file because it's the structure (and not the actual contents) that counts at this time.

Figure 13.4. First page of Data Binding Wizard.

graphics/13fig04.jpg

However, instead of starting the XML Data Binding Wizard from the Object Repository, we can also start it by double-clicking the TXMLDocument component. This will make sure the XML Data Binding Wizard is already loaded with the XML Document that was specified by the TXMLDocument component itself, moving us to the second page of the Data Binding Wizard automatically (see Figure 13.5).

Figure 13.5. Second page of Data Binding Wizard.

graphics/13fig05.jpg

On this second page of the XML Data Binding Wizard we get an overview that shows how the Wizard will represent each XML element, and which source code types or elements will be generated. As you can see in Figure 13.5, there are a number of complex types ( ChapterType , SectionType ) as well as simple types ( string ) used by our XML document.

A helpful feature of this second page is the fact that we can still modify everything, including the access mode of attributed and child nodes, which is very useful. By default set to Read/Write, we can change this to Read-Only, which means an attribute value can be read, but not accidentally modified.

Before we move on to the last page, let's click the Options button to view the possible options you might want to change (see Figure 13.6).

Figure 13.6. Options page of Data Binding Wizard.

graphics/13fig06.jpg

As you can see in Figure 13.6, we can change some of the code that will be generated, such as the Get_ and Set_ prefixes for the getter and setter routines. The Data Type map is not useful for this example because we only use the String type, but it might be convenient when you want to use custom types at a later time.

When you're ready, close the XML Data Binding Wizard Options dialog, and click the Next button to go to the third and last page of the XML Data Binding Wizard (which can be seen in Figure 13.7).

Figure 13.7. Third page of Data Binding Wizard.

graphics/13fig07.jpg

This third and last page of the XML Data Binding Wizard is only used as information again, and in our case displays two generated interfaces: IXMLChapterType and IXMLSectionType (and the C++Builder editions _di_IXMLChapterType and _di_IXML SectionType) . For both types, we can preview the generated interface definition, for which the properties are most interesting. The IXMLChapterType contains a Title as well as Section (array) property to access the Title attribute and the Section child nodes. The IXMLSectionType will contain properties for Title , Components , and Wizards . We can decide to store the binding settings for later use in the suggested file BizSnap.xdb (this file can be reused at the first page of the Data Binding Wizard). When we click the Finish button, the source code for the interfaces will be generated in a new unit that will be added to the current project. Save this new unit as BizSnap.cpp , so we know where it belongs. The definitions of the new interfaces and classes can be read in the BizSnap.h file, and are as shown in Listing 13.1.

Listing 13.1 XML Data Binding “Generated BizSnap.h
 // ***************************************** //  //  //            XML Data Binding  //  //         Generated on: 2002-08-04 23:14:19  //       Generated from: BizSnap.xml  //   Settings stored in: BizSnap.xdb  //  // ***************************************** //  #ifndef   BizSnapH  #define   BizSnapH  #include <System.hpp>  #include <xmldom.hpp>  #include <XMLDoc.hpp>  #include <XMLIntf.hpp>  #include <XMLNodeImp.h>  // Forward Decls  __interface IXMLChapterType;  typedef System::DelphiInterface<IXMLChapterType> _di_IXMLChapterType;  __interface IXMLSectionType;  typedef System::DelphiInterface<IXMLSectionType> _di_IXMLSectionType;  // IXMLChapterType  __interface INTERFACE_UUID("{2E7DECFE-0AD3-43BB-BEF7-24FAAF467567}")  IXMLChapterType : public IXMLNodeCollection  {  public:  public:    // Property Accessors    virtual WideString __fastcall Get_Title() = 0;    virtual _di_IXMLSectionType __fastcall Get_Section(int Index) = 0;    virtual void __fastcall Set_Title(WideString Value) = 0;    // Methods & Properties    virtual _di_IXMLSectionType __fastcall Add() = 0;    virtual _di_IXMLSectionType __fastcall Insert(const int Index) = 0;    __property WideString Title = { read=Get_Title, write=Set_Title };    __property _di_IXMLSectionType Section[int Index] = { read=Get_Section };  };  // IXMLSectionType  __interface INTERFACE_UUID("{F85BA1A2-DB61-42AC-A95C-74F8710FA90C}")  IXMLSectionType : public IXMLNode  {  public:    // Property Accessors    virtual WideString __fastcall Get_Title() = 0;    virtual WideString __fastcall Get_Components() = 0;    virtual WideString __fastcall Get_Wizards() = 0;    virtual void __fastcall Set_Title(WideString Value) = 0;    virtual void __fastcall Set_Components(WideString Value) = 0;    virtual void __fastcall Set_Wizards(WideString Value) = 0;    // Methods & Properties    __property WideString Title = { read=Get_Title, write=Set_Title };    __property WideString Components = { read=Get_Components, write=Set_Components };    __property WideString Wizards = { read=Get_Wizards, write=Set_Wizards };  };  // Forward Decls  class TXMLChapterType;  class TXMLSectionType;  // TXMLChapterType  class TXMLChapterType : public TXMLNodeCollection, public IXMLChapterType  {    __IXMLNODECOLLECTION_IMPL__  protected:    // IXMLChapterType    virtual WideString __fastcall Get_Title();    virtual _di_IXMLSectionType __fastcall Get_Section(int Index);    virtual void __fastcall Set_Title(WideString Value);    virtual _di_IXMLSectionType __fastcall Add();    virtual _di_IXMLSectionType __fastcall Insert(const int Index);  public:    virtual void __fastcall AfterConstruction(void);  };  // TXMLSectionType  class TXMLSectionType : public TXMLNode, public IXMLSectionType  {    __IXMLNODE_IMPL__  protected:    // IXMLSectionType    virtual WideString __fastcall Get_Title();    virtual WideString __fastcall Get_Components();    virtual WideString __fastcall Get_Wizards();    virtual void __fastcall Set_Title(WideString Value);    virtual void __fastcall Set_Components(WideString Value);    virtual void __fastcall Set_Wizards(WideString Value);  };  // Global Functions  _di_IXMLChapterType __fastcall GetChapter(_di_IXMLDocument Doc);  _di_IXMLChapterType __fastcall GetChapter(TXMLDocument *Doc);  _di_IXMLChapterType __fastcall LoadChapter(const WideString FileName);  _di_IXMLChapterType __fastcall  NewChapter();  #endif  

As we can see from Listing 13.1, there are two new interface types: IXMLChapterType and IXMLSectionType , which we saw earlier in the last page of the XML Data Binding Wizard, together with their _di_IXMLChapterType and _di_IXMLSectionType C++Builder interface typecasts .

What's even more useful is the fact that the new unit also contains the class definitions (in BizSnap.h ) and implementations (in BizSnap.cpp ) for TXMLChapterType and TXMLSectionType . TXMLChapterType is derived from TXMLNodeCollection (it contains child nodes), and TXMLSectionType is derived from TXMLNode . Both implement their similar-named interface.

That's not all, because the BizSnap unit also contains three global functions: GetChapter() (overloaded), LoadChapter() , and NewChapter() . The first can be used to extract a Chapter from an existing TXMLDocument component or _di_XMLDocument interface. The second can be used to load a Chapter from an existing, compatible XML file (such as the BizSnap.xml file), and the NewChapter() function can be used to start a new, empty, Chapter. All three return a _di_IXMLChapterType interface, which can then be used to work with C++Builder.

As an example, let's use the GetChapter() function to extract the _di_IXMLChapterType from the TXMLDocument component and work with it using the named methods and properties. First, we must add the BizSnap header to the includes section of our main form (in the header file of our main form), so we can use the interface types and global functions. Then, to use the _di_IXMLChapterType interface during the lifetime of the form, we can add a variable Chapter of type _di_IXMLChapterType to the form (place it in the private section). Also, add a private field called CurrentSection of type int , and a private method called DisplaySection() , as follows :

 #include <BizSnap.h>  //                                      - class TForm1 : public TForm  {  __published:  // IDE-managed Components          TXMLDocument *XMLDocument1;          TMemo *Memo1;          TButton *btnXML;          TButton *btnFirst;          TButton *btnPrev;          TButton *btnNext;          TButton *btnLast;          void __fastcall btnXMLClick(TObject *Sender);  private:      // User declarations          _di_IXMLChapterType Chapter;          int CurrentSection;          void DisplaySection(void);  public:       // User declarations          __fastcall TForm1(TComponent* Owner);  }; 

Now, write the following code for the OnCreate() event handler of the Form, as well as the private method DisplaySection() :

 void __fastcall TForm1::FormCreate(TObject *Sender)  {    Chapter = GetChapter(XMLDocument1);    CurrentSection = 0; // First Section    DisplaySection();  }  void TForm1::DisplaySection(void)  {    Memo1->Lines->Clear();    Memo1->Lines->Add("Chapter: " + Chapter->Title);    Memo1->Lines->Add("Section: " +      Chapter->Section[CurrentSection]->Title);    Memo1->Lines->Add("Components: " +      Chapter->Section[CurrentSection]->Components);    Memo1->Lines->Add("Wizards: " +      Chapter->Section[CurrentSection]->Wizards);  } 

As you'll find out when you type along, the Code Insight features of the C++Builder 6 IDE will now help us when writing code. Specifically, if you type GetChapter() , you will be helped with the argument. When you want to use the Chapter (of type _di_IXMLChapterType ), Code Insight will show you a list of available properties and methods. No more accidental typing mistakes resulting in modified XML documents with nonsense child nodes.

Now, let's add four TButton components, called btnFirst , btnPrev , btnNext , and btnLast . Write the following code for their OnClick event handler (to display information from the first, previous, next, and last section).

 void __fastcall TForm1::btnFirstClick(TObject *Sender)  {    CurrentSection = 0;    DisplaySection();  }  void __fastcall TForm1::btnPrevClick(TObject *Sender)  {    if (CurrentSection)    {      CurrentSection;      DisplaySection();    }  }  void __fastcall TForm1::btnNextClick(TObject *Sender)  {    if (CurrentSection < Chapter->Count-1)    {      CurrentSection++;      DisplaySection();    }  }  void __fastcall TForm1::btnLastClick(TObject *Sender)  {    CurrentSection = Chapter->Count-1;    DisplaySection();  } 

We can now view the contents of one item of the XML document inside the TMemo control and use the Next and Prev buttons to navigate through the XML document (see Figure 13.8 for the application in action).

Figure 13.8. XML Data Binding in action.

graphics/13fig08.gif

As a final enhancement, we can disable the First/Prev buttons if we are showing the first section, and enable them otherwise . Similarly, we can disable the Last/Next buttons if we are showing the last section, and enable them otherwise. This is done by adding a few lines of code to the private DisplaySection() method.

 void TForm1::DisplaySection(void)  {    Memo1->Lines->Clear();    Memo1->Lines->Add("Chapter: " + Chapter->Title);    Memo1->Lines->Add("Section: " +      Chapter->Section[CurrentSection]->Title);    Memo1->Lines->Add("Components: " +      Chapter->Section[CurrentSection]->Components);    Memo1->Lines->Add("Wizards: " +      Chapter->Section[CurrentSection]->Wizards);    // Enable/disable buttons    btnFirst->Enabled = CurrentSection > 0;    btnPrev->Enabled = CurrentSection > 0;    btnNext->Enabled = CurrentSection < Chapter->Count-1;    btnLast->Enabled = CurrentSection < Chapter->Count-1;  } 

This concludes the XML Document Programming using Data Binding example. As you might have experienced yourself, the generated interfaces and support classes greatly enhance the functionality of the plain _di_IXMLDocument capabilities.


   
Top


C++ Builder Developers Guide
C++Builder 5 Developers Guide
ISBN: 0672319721
EAN: 2147483647
Year: 2002
Pages: 253

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net