MSXML C++ Wrapper Class

Loading, Parsing, and Saving XML Documents.

This article was contributed by Sébastien ANDRE.

Environment: MFC / VC++ / Windows with MSXML library

This article presents my work for managing XML documents into a VC++ application.I made this class with the help of Tom Archer's source code found on the CodeGuru Web site. For my personal application, I need to be able to load, parse, and save an XML document. I performed many searches but only the "Tom Archer" source code satisfied me. From his code, I decided to create a class to give me an EASY way to use XML documents.

The goal of this class isn't to have the "Best" perfomances but only to have an EASY way to use XML documents, and, at the same time, to have a "readable code"!!!

For more details on how you can use MSXML library, go to see this article from Tom Archer Introduction to Using the XML DOM from Visual C++.


Update version: I have updated this class to improve it, correct some bugss, and add some new features:

  • We can now manage an XML header with two methods: "Set_Header()" and "Get_Header()"
  • We can Load/Create CDATA sections easily
  • XML representation is now available and some methods had been renamed for a better design

So how do you use this class? The best way is to see it in a little example !!!!

The first step is to take an XML Document to load and parse, as in the following example:

1. Loading and Parsing XML Documents

   <?xml version="1.0"?>
   <FAMILY name="Smith">
        <FATHER age="45"> John </FATHER>
        <MOTHER age="38" birthname="Griffith"> Barbara </MOTHER>
        <CHILDREN age="8" sex="Male"> Arthur </CHILDREN>
        <CHILDREN age="4" sex="Female"> Stephany </CHILDREN>
        <NOTE> <![CDATA[ A happy family !! ]]> </NOTE>
   </FAMILY>

It's an easy document to load and simplify this guide. The goal now is to be able to store all informations in a C++ object!! This step will describe the CLASS INTERFACE to store the XML document:

   class FAMILY
   {    public:
           void SetName(LPCTSTR Name);

           void SetFatherName(LPCTSTR FirstName);
           void SetFatherAge(int);

           void SetMotherName(LPCTSTR FirstName);
           void SetMotherBirthName(LPCTSTR BirthName);
           void SetMotherAge(int Age);

           void Add_Children();
           void Set_LastChildrenName(LPCTSTR FirstName);
           void Set_LastChildrenAge(int age);
           void Set_LastChildrenSex(LPCTSTR Gender);

           void Set_Note(LPCTSTR note);
           void Get_Note(CString & note);
   }

This class must derive from the XML_PARSER class to be able to load an XML document and it must implement the Parse_XML_Document method. It's on this method that the program loads informations into our class.

P.S.: The Parse_XML_Document method is called when you load an XML Document with Load_XML_Document. For EACH node found on the loaded document, a call is perfomed to Parse_XML_Document to let the programmer do any action.

   class FAMILY: public XML_PARSER
   {    public:
            void Parse_XML_Document();    // NEEDED to PARSE the
                                          // LOADED Document

            void SetName(LPCTSTR Name);

            void SetFatherName(LPCTSTR FirstName);
            void SetFatherAge(int);

            void SetMotherName(LPCTSTR FirstName);
            void SetMotherBirthName(LPCTSTR BirthName);
            void SetMotherAge(int Age);

            void Add_Children();
            void Set_LastChildrenName(LPCTSTR FirstName);
            void Set_LastChildrenAge(int age);
            void Set_LastChildrenSex(LPCTSTR Gender);

            void Set_Note(LPCTSTR note);
            void Get_Note(CString & note);
   }

Now, we will implement the "Parse_XML_Document" method:

   void FAMILY::Parse_XML_Document()
   {   // For each node we store data
       //

       // If it's a FAMILY Node, and the Root node
       //
       if( Is_Root() && Is_Tag("<FAMILY>") )
       {   // Handle Attributes
           //
           if( Is_Having_Attribute("name") )
               this->SetName( Get_Attribute_Value() );
       }

       // If it's the FATHER Node in a FAMILY node
       //
       if( Is_Tag("<FATHER>") && Is_Child_of("<FAMILY>") )
       {   // Handle Attributes
           //
           if( Is_Having_Attribute("age") )
           {   int age;
               sscanf( Get_Attribute_Value() , "%d" , &age);
               this->SetFatherAge(age);
           }
       }

       // If it's the FATHER TEXT
       //
       if( Is_TextNode() && Is_Child_of("<FAMILY><FATHER>") )
       {   // Set the FirstName
           //
           this->SetFatherName( Get_TextValue() );
       }

       // If it's the MOTHER Node in a FAMILY node
       //
       if( Is_Tag("<MOTHER>") && Is_Child_of("<FAMILY>") )
       {   // Handle Attributes
           //
           if( Is_Having_Attribute("age") )
           {   int age;
               sscanf( Get_Attribute_Value() , "%d" , &age);
               this->SetMotherAge(age);
           }

           if( Is_Having_Attribute("birthname") )
               this->SetMotherBirthName( Get_Attribute_Value() );
       }

       // If it's the MOTHER TEXT
       //
       if( Is_TextNode() && Is_Child_of("<FAMILY><MOTHER>") )
       {   // Set the FirstName
           //
           >this->SetMotherName( Get_TextValue() );
       }

       // If it's the CHILDREN Node in a FAMILY node
       //
       if( Is_Tag("<CHILDREN>") && Is_Child_of("<FAMILY>") )
       {   // Add a Children
           //
           this->Add_Children();

           // Handle Attributes
           //
           if( Is_Having_Attribute("age") )
           {   int age;
               sscanf( Get_Attribute_Value() , "%d" , &age);
               this->Set_LastChildrenAge(age);
           }

           if( Is_Having_Attribute("sex") )
               this->Set_LastChildrenSex( Get_Attribute_Value() );
       }

       // If it's the CHILDREN TEXT Node
       //
       if( Is_TextNode() && Is_Child_of("<FAMILY><CHILDREN>") )
       {   // Set the FirstName
           //
           this->Set_LastChildrenName( Get_TextValue() );
       }

       // If it's the CDATA section on NOTE node
       //
       if(Is_Child_of("<NOTE>") && Is_CDataSection())
       {   // Set the Note value
           //
           CString val;
           val = this->Get_TextValue();
           this->Set_Note(val);
       }
   }

So, you can use it in the main program code like this:

   FAMILY a_family;
   a_family.Load_XML_Document("example.xml");

And the example.xml file is parsed and stored into your FAMILY Object! So, now we have concluded the loading and parsing capabilities, but when I wrote this class, my second goal was to be able to create an XML document!!

2. Creating and Saving XML Documents

After many searches, I found a way to do it, but by the same token, my principal interest is to keep the code "readable and easy." To construct an XML document, I wrote some methods that permit me to create a node, moving into the current document.

The best way to see how it work is again a little example. For this one, our goal is to write this document:

   <?xml version="1.0" encoding="UTF-8" ?>
   <MOVIE filename="SpiderMan.avi">
      <NAME>SpiderMan</NAME>
      <LENGTH value="110"/>
      <ACTORS>
           <ACTOR>Tobey Maguire</ACTOR>
           <ACTOR>Willem Dafoe</ACTOR>
      </ACTORS>
      <DIRECTOR>Sam Raimi</DIRECTOR>
      <SUBTITLE>French</SUBTITLE>
      <SUBTITLE>English</SUBTITLE>
   </MOVIE>

So the code could be like this:

   Reset_XML_Document();
                   // Reset Content of XML Document
   Set_Header("xml","encoding","UTF-");
                   // Set the encoding property

   // Create the root node.
   // (We use Add_FirstChildNode because we have no node;
   // it creates the root node.)
   //
   Add_FirstChildNode("MOVIE");
   Set_Attribute("filename","SpiderMan.avi");

   // Now the current node is the <MOVIE> Node (the root node).
   // To move into the document, start by creating the <ACTORS>
   // node.
   // 
   Add_FirstChildNode("ACTORS");

   //Now the current node is the <ACTORS> node.
   //
   Add_LastChildNode("ACTOR");
   Set_TextValue("Willem Dafoe");

   // Now the current node is the <ACTOR> node.
   // We can't use Add_FirstChildNode or Add_LastChildNode to
   // create the second <ACTOR> node because it's not a child
   // node for the first <ACTOR> that was just created.
   // We have two ways to accomplish this: Move to the parent Node
   // <ACTORS> or create directly before the current node.
   //

   // First way -->
   Go_to_Parent("ACTORS");
   Add_FirstChildNode("ACTOR");
   Set_TextValue("Tobey Maguire");

   // Second way -->
   Add_NodeBefore("ACTOR");
                // Add a new node before the current node
                // (both have same parent).
   Set_text("Tobey Maguire");

   // Add <NAME> && <LENGTH> nodes
   //
   Go_to_Root();
   Add_FirstChildNode("LENGTH");
   Set_Attribute("value","110");
   Go_to_Root();
   Add_FirstChildNode("Name");
   Set_TextValue("SpiderMan");

   // Add the Director Node. We move to the ACTORS node, and
   // we create the DIRECTOR node after this.
   //
   Go_Forward("ACTORS");
   Add_NodeAfter("DIRECTOR");
   Set_TextValue("Sam Raimi");

   // Add both Subtitle node, at least two ways are possible:
   //

   // Way 1:
   //
   Go_to_Root();
   Add_LastChildNode("SUBTITLE");
   Set_TextValue("French");
   Go_to_Root();
   Add_LastChildNode("SUBTITLE");
   Set_TextValue("English");

   // Way 2:
   //
   Add_NodeAfter("SUBTITLE");
   Set_TextValue("French");
   Add_NodeAfter("SUBTITLE");
   Set_TextValue("English");

   // Way 3:
   //
   Add_NodeAfter("SUBTITLE");
   Set_TextValue("English");
   Add_NodeBefore("SUBTITLE");
   Set_TextValue("French");

The document is now done. We can save it by using this method:

   Save_XML_Document("SpiderMan.xml");

It's ended. The classes have more methods; you can see the include header file. I put in some comments to let all users understand what each method means.

If you have any questions, you can send me an e-mail at maximus@oreka.com. I hope that this class can help someone.

Downloads

XML_PARSER class source code - 10 Kb


Comments

  • BVruw lkV DPrJ

    Posted by fqANTHbWla on 11/14/2012 10:24am

    carisoprodol no prescription 350 mg carisoprodol generic soma - carisoprodol 350 mg tablets information

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds