Click here to Skip to main content
15,883,795 members
Articles / Mobile Apps

Using MSXML to Read XML Documents

Rate me:
Please Sign up or sign in to vote.
4.40/5 (36 votes)
7 Jun 2003Public Domain2 min read 368K   4.7K   73  
How to read XML documents using MSXML, in a modern C++/template manner
#include <windows.h>
#include <msxml.h>
#include <objsafe.h>
#include <objbase.h>
#include <atlbase.h>
#pragma warning( push )
#pragma warning( disable: 4018 4786)
#include <string>
#pragma warning( pop )
using namespace std;



const wchar_t *src=L""
  L"<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n"
  L"<root desc=\"Simple Prog\">\r\n"
  L"  <text>Hello World</text>\r\n"
  L"    <layouts>\r\n"
  L"    <lay pos=\"15\" bold=\"true\"/>\r\n"
  L"    <layoff pos=\"12\"/>\r\n"
  L"    <layin pos=\"17\"/>\r\n"
  L"  </layouts>\r\n"
  L"</root>\r\n";




// TElem -- a simple class to wrap up IXMLDomElement and iterat its children.
//   name()    - in <item>stuff</item> it returns "item"
//   val()     - in <item>stuff</item> it returns "stuff"
//   attr(s)   - in <item s=L"hello">stuff</item> it returns "hello"
//   subnode(b)- in <item><a>hello</a><b>there</b></item> it returns the TElem <b>there</b>
//   subval(b) - in <item><a>hello</a><b>there</b></item> it returns "there"
//   for (TElem c=e.begin(); c!=e.end(); c++) {...} - iterators over the subnodes
struct TElem
{ CComPtr<IXMLDOMElement> elem;
  CComPtr<IXMLDOMNodeList> nlist; int pos; long clen;
  //
  TElem() : elem(0), nlist(0), pos(-1), clen(0) {}
  TElem(int _clen) : elem(0), nlist(0), pos(-1), clen(_clen) {}
  TElem(CComPtr<IXMLDOMElement> _elem) : elem(_elem), nlist(0), pos(-1), clen(0) {get();}
  TElem(CComPtr<IXMLDOMNodeList> _nlist) : elem(0), nlist(_nlist), pos(0), clen(0) {get();}
  void get()
  { if (pos!=-1)
    { elem=0;
      CComPtr<IXMLDOMNode> inode;
      nlist->get_item(pos,&inode);
      if (inode==0) return;
      DOMNodeType type; inode->get_nodeType(&type);
      if (type!=NODE_ELEMENT) return;
      CComQIPtr<IXMLDOMElement> e(inode);
      elem=e;
    }
    clen=0; if (elem!=0)
    { CComPtr<IXMLDOMNodeList> iNodeList;
      elem->get_childNodes(&iNodeList);
      iNodeList->get_length(&clen);  
    }
  }
  //
  wstring name() const
  { if (!elem) return L"";
    CComBSTR bn; elem->get_tagName(&bn);
    return wstring(bn);
  }
  wstring attr(const wstring name) const
  { if (!elem) return L"";
    CComBSTR bname(name.c_str());
    CComVariant val(VT_EMPTY);
    elem->getAttribute(bname,&val);
    if (val.vt==VT_BSTR) return val.bstrVal;
    return L"";
  }
  bool attrBool(const wstring name,bool def) const
  { wstring a = attr(name);
    if (a==L"true" || a==L"TRUE") return true;
    else if (a==L"false" || a==L"FALSE") return false;
    else return def;
  }
  int attrInt(const wstring name, int def) const
  { wstring a = attr(name);
    int i, res=swscanf(a.c_str(),L"%i",&i);
    if (res==1) return i; else return def;
  }
  wstring val() const
  { if (!elem) return L"";
    CComVariant val(VT_EMPTY);
    elem->get_nodeTypedValue(&val);
    if (val.vt==VT_BSTR) return val.bstrVal;
    return L"";
  }
  TElem subnode(const wstring name) const
  { if (!elem) return TElem();
    for (TElem c=begin(); c!=end(); c++)
    { if (c.name()==name) return c;
    }
    return TElem();
  }
  wstring subval(const wstring name) const
  { if (!elem) return L"";
    TElem c=subnode(name);
    return c.val();
  }
  TElem begin() const
  { if (!elem) return TElem();
    CComPtr<IXMLDOMNodeList> iNodeList;
    elem->get_childNodes(&iNodeList);
    return TElem(iNodeList);
  }
  TElem end() const
  { return TElem(clen);
  }
  TElem operator++(int)
  { if (pos!=-1) {pos++; get();}
    return *this;
  }
  bool operator!=(const TElem &e) const
  { return pos!=e.clen;
  }
};




void test()
{
  CComPtr<IXMLDOMDocument> iXMLDoc;
  iXMLDoc.CoCreateInstance(__uuidof(DOMDocument));
 	
  // Following is a bugfix for PocketPC.
#ifdef _UNDER_CE
  gargle bargle
  iXMLDoc->put_async(VARIANT_FALSE);
  CComQIPtr<IObjectSafety,&IID_IObjectSafety> iSafety(iXMLDoc);
  if (iSafety) 
  { DWORD dwSupported, dwEnabled; 
    iSafety->GetInterfaceSafetyOptions(IID_IXMLDOMDocument,&dwSupported,&dwEnabled);
    iSafety->SetInterfaceSafetyOptions(IID_IXMLDOMDocument,dwSupported,0);
  }
#endif

  // Load the file. 
  VARIANT_BOOL bSuccess=false;
  // Can load it from a url/filename...
  //iXMLDoc->load(CComVariant(url),&bSuccess);
  // or from a BSTR...
  iXMLDoc->loadXML(CComBSTR(src),&bSuccess);

  // Get a pointer to the root
  CComPtr<IXMLDOMElement> iRootElm;
  iXMLDoc->get_documentElement(&iRootElm);

  // Thanks to the magic of CComPtr, we never need call
  // Release() -- that gets done automatically.


  TElem eroot(iRootElm);
  wstring desc = eroot.attr(L"desc");
  // returns "Simple Prog"

  TElem etext = eroot.subnode(L"text");
  wstring s = etext.val();
  // returns "Hello World"
  s = eroot.subval(L"text");
  // This is a shorter way to achieve the same thing

  TElem elays = eroot.subnode(L"layouts");
  for (TElem e=elays.begin(); e!=elays.end(); e++)
  { int pos = e.attrInt(L"pos",-1);
    bool bold = e.attrBool(L"bold",false);
    // we suggest default values, in case the attribute is missing
    wstring id = e.name();
    // returns "lay" or "layoff" or "layin"
  }
}




#ifdef UNDER_CE
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPTSTR,int)
{ CoInitializeEx(NULL,COINIT_MULTITHREADED);
  test();
  CoUninitialize();
  return 0;
}
#else
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{ CoInitialize(NULL);
  test();
  CoUninitialize();
  return 0;
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Technical Lead
United States United States
Lucian studied theoretical computer science in Cambridge and Bologna, and then moved into the computer industry. Since 2004 he's been paid to do what he loves -- designing and implementing programming languages! The articles he writes on CodeProject are entirely his own personal hobby work, and do not represent the position or guidance of the company he works for. (He's on the VB/C# language team at Microsoft).

Comments and Discussions