Click here to Skip to main content
Click here to Skip to main content

Object-oriented XML Parser

, 28 Aug 2001
Rate this:
Please Sign up or sign in to vote.
Object-oriented parser to read/write XML files using MSXML parser

Introduction

I had a task to write an XML parser to read/write XML files with list of possibilities (requirements).

Requirements:

  • Comfort for developer (user of parser)
  • Possibility of recording and reading using the same instance of parser
  • No use of MFC
  • User object writes and reads itself
  • Possibility to write in binary stream, without changing source of user objects
  • Possibility of creation of proxy classes for reading/writing of user classes, modification of which is forbidden
  • Same code in user object for reading and writing
  • Possibility of reading/writing simple types
  • Possibility of reading/writing objects (with possibility of determination of type during loading)
  • Possibility of reading/writing vector, map of simple and complex objects
  • Possibility of reading/writing the attributes
  • Absences of restrictions on nesting of one type in others
  • Minimization of operations "if"
  • Unimportance of order of tags in parent tag
  • Absence of support namespace and schema

Solution

Based on several ideas:

  1. Using of parser-a based on sample from Windows Platform SDK
  2. Each user object that understand that it is his time to be read, throws itself just like "throw this"
  3. Than parser catch him and put into stack and all calls will be send to this object, until anyone else throw itself or end of object will be found
  4. Each user object have only one function "determine(ProxyObject& proxy)" it should ovewrite
  5. Proxy - it is an abstract object that have some virtual functions to read/write some types of data and proxy implementations which are made automaticaly by parser to exactly "know" the type of stream and current operation
  6. There is a template class with template constructor, that gets members of user objects, proxy object, "name" of the object to read
  7. This template class understands itself what to do with that members and call corresponding proxy's functions.
  8. There are some proxy classes that can read/write string, int and float.

Here is that wonderful template:

template <class T = void*>
class determineMember
{
    public:
    template <class OT>
    determineMember(OT& t, 
        const char* str,XmlParserProxy& p,T* _t=0) throw(XmlObject*)
    {
        determine(t,str,p,_t,type(t));
    }
};

Currently my parser satisfies all requirements above. And this is example of user objects:

struct Nodes : XmlObject
{
    vectorDel<Node*>  m_nodes;
    virtual void determine(XmlParserProxy& p) throw(XmlObject*)
    {
        determineMember<StartNode>(m_nodes,"start-node",p);
        determineMember<InteractionNode>(m_nodes,"interaction-node",p);
    }
};
struct Pipeline : XmlObject
{
  string m_name;
  int    m_count;
  float  m_sum;
  SomeObject* m_someObject;
  vector<string> m_transitions;
  vector<int> m_point;
  Nodes m_nodes;
  map<int,NodeDisplay> m_map;
  virtual void determine(XmlParserProxy& p) throw(XmlObject*)
  {
    determineMember<>(m_name,"name",p);
    determineMember<>(m_count,"count",p);
    determineMember<>(m_sum,"sum",p);
    determineMember<FirstObject>(m_someObject,"FirstObject",p);
    determineMember<SecondObject>(m_someObject,"SecondObject",p);
    determineMember<Nodes>(m_nodes,"nodes",p);
    determineMember<string>(m_transitions,"transition",p);
    determineMember<int>(m_point,"point",p);
    determineMember<>(m_map,"Map",p);
  }
};

Note that you can have pointers and vectors of objects and have different classes there.

This is an example of using the parser:

CoInitialize(NULL);

Document doc;
XML::ZXmlParserImpl parser(&doc);

parser.parse(_bstr_t("test.xml"));

parser.save(_bstr_t("saved_test.xml"));

CoUninitialize();

Look at this sample XML file:

<pipeline>
   <!-- string -->
        <name>Default</name>
        <!-- int -->
         <count>2</count>
        <!-- float -->
         <sum>1.234567</sum>
        <!-- object having type from set of types-->
        <SecondObject>
          <second>1</second>
        </SecondObject>
         <!-- uncomment FirstObject and comment SecondObject 
                     to make FirstObject instead of SecondObject
        <FirstObject>
          <first>1</first>
        </FirstObject>
        -->
        <!-- new XMLObject of type Nodes-->
        <nodes>
                <!-- insert in vector<Node> new StartNode, 
                                               string attribute-->
                <start-node id="Start">
                        <!-- insert vector<NodeDisplay> new NodeDisplay-->
                        <node-display>
                <x-center>0</x-center>
                <y-center>0</y-center>
            </node-display>
            <node-display>
                                <x-center>1</x-center>
                                <y-center>1</y-center>
            </node-display>
        </start-node>
                <!-- insert in vector<Node> 
                        new InteractionNode, string attribute-->
                <interaction-node id="It">

                    <!-- two string attributes-->
                   <template dynamic="false" index="2">
                           testS
                   </template>
                </interaction-node>
    </nodes>

<!-- vector of strings -->
        <transition>Tr1</transition>
        <transition>Tr2</transition>

<!-- vector of ints -->
        <point>3</point>
        <point>2</point>
        <point>1</point>

<!-- and now - std::map<int,NodeDisplay> -->
        <Map>
          <pair>
            <name>1</name>
            <value>
                <x-center>1</x-center>
                <y-center>2</y-center>
            </value>
          </pair>
          <pair>
            <name>2</name>
            <value>
                <x-center>4</x-center>
                <y-center>3</y-center>
            </value>
          </pair>
        </Map>

</pipeline>

This table shows how to implement determine function with different members

Member variable Source in determine Comments
string m_name; determineMember<>(m_name,"name",p);  
string m_name; determineMember<AtribValue>(m_name,"name",p); Use AtribValue to indicate that name is attribute but not a node
int m_count; determineMember<>(m_name,"count",p);  
float m_sum; determineMember<>(m_name,"sum",p);  
SomeObject* m_someObject; determineMember <FirstObject>(m_someObject, "FirstObject",p); If tag FirstObject found, then new FirstObject will be assigned to m_someObject
SomeObject* m_someObject; determineMember <SecondObject>(m_someObject, "SecondObject",p); If tag SecondObject found, then new SecondObjectwill be assigned to m_someObject
SomeObject m_nodes; determineMember<>(m_nodes,"nodes",p);  
std::vector<int> m_point; determineMember<int>(m_point,"point",p);  
std::vector<string> m_transitions; determineMember <string>(m_transitions, "transition",p);  
std::map<int,SomeObject> m_map; determineMember<>(m_map,"Map",p);  
std::vector<Node*> m_nodes determineMember<StartNode>(m_nodes,"start-node",p); If tag start-node found, then new StartNode will be made and inserted in m_nodes
std::vector<Node*> m_nodes; determineMember <InteractionNode>(m_nodes, "interaction-node",p); If tag interaction-node found, then new InteractionNode will be made and inserted in m_nodes

In demo project I have shown how to implement classes for reading/writing std::map not in parser's source files.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Mike Melnikov
Web Developer
Russian Federation Russian Federation
Mike has been programming in C/C++ for 11 years and Visual C++/MFC for 4 years. His background includes pure and applied mathematics, engineering and physics, and he is currently based in Moscow, Russia.

Comments and Discussions

 
GeneralCompile errors PinmemberMember 6681898-May-08 13:14 
QuestionHo do i add MSXMl6.dll to my installer ? Pinmembercode4jigar5-Sep-06 2:18 
AnswerRe: Ho do i add MSXMl6.dll to my installer ? PinmemberMike Melnikov29-Sep-06 14:01 
GeneralWriting to an XML file Pinmemberwcovuaku28-Oct-04 5:56 
GeneralRe: Writing to an XML file PinmemberMike Melnikov28-Oct-04 19:07 
QuestionHow to serialize custom map&lt;CString,Object** &gt;? Pinmembervgrigor13-Oct-04 22:23 
Generalsome problems: map - error Pinmembervgrigor13-Oct-04 20:41 
GeneralHelp please PinsussAnonymous25-Aug-04 22:38 
GeneralRe: Help please PinmemberColin Angus Mackay25-Aug-04 23:43 
GeneralVisual Studio .NET 2003 PinmemberSevig11-Jul-04 20:22 
GeneralRe: Visual Studio .NET 2003 PinmemberMike Melnikov25-Aug-04 22:55 
Generallitle trouble with charsets PinmemberAlex V. Kayuchkin15-Jan-04 21:47 
GeneralRe: litle trouble with charsets PinmemberMike Melnikov15-Jan-04 22:56 
GeneralRe: litle trouble with charsets PinmemberaGodInHost1-May-04 5:30 
GeneralProblem with MFC release.. PinmemberEPulse21-Dec-03 17:45 
GeneralRe: Problem with MFC release.. PinmemberEPulse21-Dec-03 20:52 
GeneralLimitation PinmemberSahbi15-Jun-03 0:45 
GeneralRe: Limitation PinmemberMike Melnikov25-Jun-03 0:49 
Generalabout attribute and one advise Pinmembermarco.song13-May-03 16:04 
Generaljust get string, don't save to file. Pinmembermarco.song10-May-03 8:07 
GeneralRe: just get string, don't save to file. PinmemberMike Melnikov11-May-03 23:03 
GeneralRe: just get string, don't save to file. Pinmembermarco.song13-May-03 15:56 
GeneralProblem after fixing the memory leaks PinmemberItay Szekely3-Apr-03 5:51 
GeneralQuestion about progam flow PinmemberPankaj Kumar7-Jan-03 19:51 
Questionwhat about header? Pinmembergok19-Dec-02 13:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 29 Aug 2001
Article Copyright 2001 by Mike Melnikov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid