Click here to Skip to main content
Licence 
First Posted 29 Feb 2004
Views 23,112
Bookmarked 17 times

RTSXML Parser

By | 29 Feb 2004 | Article
Extension of Object Oriented XML Parser.

Introduction

I have a project to develop flexible menus and screens, and I am thinking to use XML as my format for the configuration file.

Thanks to Mike Melnikov. I read his project: "object-oriented XML parser" and I thought about how to adopt the project to mine.

Unfortunately, I have difficulty to adopt his project, because:

  • I couldn’t put his project to became one .dll library and used by another .dll library.
  • I can’t find a way to get data without ‘breaking’ the object-oriented structure.
  • I like to use classes not structures.

So, I tried to read how his project worked and reengineered his project to my XML project. I changed the name to become RTSXML.dll.

Requirement

  • I need accessing tree in a comfort way (well, at least for myself :-)).
  • I need accessing child node in an elegant way, with no ‘breaking’ the OO concept.

Solution

I am still using the parser from ‘Object-oriented XML parser’ project and developed my own tree class structured.

// read xml document and parse info CRTSXMLNode tree 
CRTSXMLNode *CRTSXMLManager::Read(LPCTSTR filename)
{
    CRTSXMLNode *pRoot = NULL; 
    if (SUCCEEDED(CreateDocument()))  // create document
    {
        if (SUCCEEDED(m_pIXMLDOMDocument->put_async(VARIANT_FALSE)))
        {
            // load and parse
            VARIANT_BOOL vSuccess = 
                m_pIXMLDOMDocument->load(_variant_t(filename)); 
            if(vSuccess)
            {
                MSXML::IXMLDOMNodePtr pNode  = m_pIXMLDOMDocument;
                if (pNode)
                {
                    pRoot = new CRTSXMLNode;
                    pRoot->m_sTitle = "Root RTSXMLDocument";
                    pRoot->m_nOrder = 1; 
                    // create a tree of xml document
                    CreateRTSXMLNode(pNode, pRoot);
                    m_pIXMLDOMDocument = NULL; 
                    return pRoot;   
                    // success
                }
            }
        }
    } 

    // error found
    ReportError(m_pIXMLDOMDocument->GetparseError());
    return NULL;
}

The concept of tree structure is like this: in every node of the tree there are some child nodes and some attribute values:

class CRTSXMLNode  

{
public:
     [..deleted…]
     CMapStringToString m_pAttrs;
     CArray<CRTSXMLNode *, CRTSXMLNode *> m_pChilds;
     [...deleted…] 
public:
     CRTSXMLNode();
     virtual ~CRTSXMLNode(); 
public:
     int GetFirstAttr(CString &key, CString &value);
     int GetNextAttr(CString &key, CString &value);
     int GetAttr(LPCTSTR key, int &value, int failedValue=-1);
     int GetAttr(LPCTSTR key, CString &value);
     int NumberOfAttrs() { return m_pAttrs.GetCount(); } 
public:
     CRTSXMLNode *GetFirstChild();
     CRTSXMLNode *GetNextChild();
     CRTSXMLNode *GetChilds(LPCTSTR key);
     CRTSXMLNode *GetChild(int nOrder);
     int NumberOfChilds() { return m_pChilds.GetUpperBound()+1; }
     CRTSXMLNode *FindChilds(LPCTSTR keyTitle); 
public:
     void AddAttr(LPCTSTR key, LPCTSTR value) { m_pAttrs.SetAt(key, value); }
     void AddChild(CRTSXMLNode *node); 

     void ReleaseAttrs();
     void ReleaseChilds(); 
public:
     void Trace(int nLevel=0); 
}

I am using CMapStringToString to keep my attribute values, because I need a fast access to the attribute without worrying about the order of attribute appearance and using CArray to keep child nodes based on order of appearance.

How to use

I am thinking “reusability” without changing anything in future projects, so I created RTSXML.dll library for those implementations.

For using the library, I created two new classes outside of the library: CXMLWindowReader and CXMLWindow.

CXMLWindowReader is a class for preparing and reading the XML file. Result of this class is CXMLNode and becomes input for CXMLWindow.

CXMLWindow is a generalization of lexical class. For this sample, I created CXMLMenu which inherited from CXMLWindow.

class EXT_WINDOW_CLASS CXMLMenu : public CXMLWindow  
{
protected:
     CMenu *m_pMenu;
     CMenu m_pBuffer[100];
     int m_nBuffer; 
protected:
     int CreateMenu(CMenu *pMenu, CRTSXMLNode *pNode); 
public:
     CXMLMenu(CMenu *pMenu = NULL);
     virtual ~CXMLMenu(); 

public:
     void SetMenu(CMenu *pMenu) { m_pMenu = pMenu; } 
public:
     int Build(CRTSXMLNode *pNode); 
};

and the important thing is implementation of int Build(CRTSXMLNode *pNode) function, which looks like this:

int CXMLMenu::Build(CRTSXMLNode *pNode)
{
     return CreateMenu(m_pMenu, pNode);
} 
int CXMLMenu::CreateMenu(CMenu *pMenu, CRTSXMLNode *pNode)
{
     CString szValue;
     CString szDesc;
     int nId; 
     CRTSXMLNode *child = pNode->GetFirstChild();
     while (child)
     {
          if (child->m_sTitle == "popup")
          {
               CMenu *pSubMenu = &m_pBuffer[m_nBuffer++]; 
               pSubMenu->CreatePopupMenu();
               child->GetAttr("menu", szValue);
               pMenu->AppendMenu(MF_POPUP, (UINT)pSubMenu->m_hMenu, szValue);
               CreateMenu(pSubMenu, child);
          }
          else
          if (child->m_sTitle == "item")
          {
               child->GetAttr("menu", szValue);
               child->GetAttr("text", szDesc);
               child->GetAttr("id", nId); 
               if (szValue == "separator")
                    pMenu->AppendMenu(MF_SEPARATOR, 0);
               else
               {
                    pMenu->AppendMenu(MF_STRING, nId, szValue);
               }
          }

          child = pNode->GetNextChild();
     }
     return 1;
}

In “menu” node (not shown in code above. See the source code) there are two kinds of child nodes: they are “popup” and “item”.

“popup” is used to define popup menu and “item” is used to define item of the menu. Every popup menu can have two child nodes: these are another popup menu and item.

For complete reference, you could download my source code. Thank you.

In my next article, I will explain how to implement frame window using XML configuration file.

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

About the Author

Hendranto Nugroho

Web Developer

Indonesia Indonesia

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Questionhow to avoid memory leaks in MSXML Pinmembergirishnadig5:19 25 Feb '05  
GeneralSuggestions PinmemberStephane Rodriguez.22:12 29 Feb '04  

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.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 1 Mar 2004
Article Copyright 2004 by Hendranto Nugroho
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid