<

Go Premium for a chance to win a PS4. Enter to Win

x

XML++

Published on
8,127 Points
5,027 Views
1 Endorsement
Last Modified:
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++.
The reason I built this class is to ease the pain of using XML files with C++, since there is no native XML support, but only through COM it is not always trivial to untrained programmer.

First the header file for the class:
File: xml++.h
#pragma once

#import "MSXML3.dll" named_guids 
#include <string>

class xmldocument;
class xmlnode;
class xmlnodelist;

class xmldocument
{
public:
	/// Constructor
	xmldocument()
	{
		CoInitialize(NULL);
		m_xmldoc.CreateInstance(MSXML2::CLSID_DOMDocument30);
		MSXML2::IXMLDOMDocument2Ptr doc = m_xmldoc;
		doc->setProperty("SelectionLanguage","XPath");
	}

	/// Loading
	bool load(std::string url)
	{
		if (m_xmldoc!=NULL) 
		{
			_variant_t v(url.c_str());
			m_xmldoc->put_async(VARIANT_FALSE);
			VARIANT_BOOL success = m_xmldoc->load(v);
			return success == VARIANT_TRUE;
		}
		return false;
	}
	bool load(std::wstring url)
	{
		if (m_xmldoc!=NULL) 
		{
			_variant_t v(url.c_str());
			m_xmldoc->put_async(VARIANT_FALSE);
			VARIANT_BOOL success = m_xmldoc->load(v);
			return success == VARIANT_TRUE;
		}
		return false;
	}

	bool save(std::string url)
	{
		_variant_t v(url.c_str());
		return m_xmldoc->save(v) == S_OK;
	}
	bool save(std::wstring url)
	{
		_variant_t v(url.c_str());
		return m_xmldoc->save(v) == S_OK;
	}

	// Access operators
	MSXML2::IXMLDOMNodePtr operator[](int index)
	{
		if (m_xmldoc!=NULL) return  m_xmldoc->childNodes->item[index];
		else return NULL;
	}
	MSXML2::IXMLDOMNodePtr operator[](std::string name)
	{
		if (m_xmldoc!=NULL) return m_xmldoc->selectSingleNode(name.c_str());
		else return NULL;
	}
	MSXML2::IXMLDOMNodePtr operator[](std::wstring name)
	{
		if (m_xmldoc!=NULL) return m_xmldoc->selectSingleNode(name.c_str());
		else return NULL;
	}

	MSXML2::IXMLDOMNodeListPtr operator()(std::string xpath)
	{
		if (m_xmldoc!=NULL) return m_xmldoc->selectNodes(xpath.c_str());
		else return NULL;
	}
	MSXML2::IXMLDOMNodeListPtr operator()(std::wstring xpath)
	{
		if (m_xmldoc!=NULL) return m_xmldoc->selectNodes(xpath.c_str());
		else return NULL;
	}

	MSXML2::IXMLDOMNodeListPtr children()
	{
		if (m_xmldoc!=NULL) return m_xmldoc->childNodes;
		else return NULL;
	}

	/// Cast operators / extractors
	operator MSXML2::IXMLDOMNodePtr()
	{
		if (m_xmldoc!=NULL) return m_xmldoc->documentElement;
		else return NULL;
	}

private:
	MSXML2::IXMLDOMDocumentPtr m_xmldoc;
};

class xmlnode
{
public:
	struct xmlvalue
	{
		_bstr_t value;
		xmlvalue() {}
		xmlvalue(_bstr_t val) { value = val; }
		
		operator std::string()
		{
			return (const char*)value;
		}
		operator std::wstring()
		{
			return (const wchar_t*)value;
		}

		operator bool()
		{
			
			if (_stricmp(value, "yes") == 0 || _stricmp(value, "true") == 0 || _stricmp(value, "1") == 0)
				return true;
			else return false;			
			return false;
		}
		operator short()
		{
			return atoi(value);
		}
		operator int()
		{
			return atoi(value);
		}
		operator long()
		{
			return atol(value);
		}
		operator unsigned short()
		{
			return atoi(value);
		}
		operator unsigned long()
		{
			return atol(value);
		}
		operator float()
		{
			return (float)atof(value);
		}
		operator double()
		{
			return atof(value);
		}
	};
public:
	xmlnode(MSXML2::IXMLDOMNodePtr source)
	{
		m_xmlnode = source;
	}	
	void operator=(MSXML2::IXMLDOMNodePtr source)
	{
			m_xmlnode = source;
	}

	xmlnode operator[](int index)
	{
		if (m_xmlnode!=NULL) return  m_xmlnode->childNodes->item[index];
		else return NULL;
	}
	xmlnode operator[](std::string name)
	{
		if (m_xmlnode!=NULL) return m_xmlnode->selectSingleNode(name.c_str());
		else return NULL;
	}
	xmlnode operator[](std::wstring name)
	{
		if (m_xmlnode!=NULL) return m_xmlnode->selectSingleNode(name.c_str());
		else return NULL;
	}

	MSXML2::IXMLDOMNodeListPtr operator()(std::string xpath)
	{
		if (m_xmlnode!=NULL) return m_xmlnode->selectNodes(xpath.c_str());
		else return NULL;
	}
	MSXML2::IXMLDOMNodeListPtr operator()(std::wstring xpath)
	{
		if (m_xmlnode!=NULL) return m_xmlnode->selectNodes(xpath.c_str());
		else return NULL;
	}


	__declspec(property(get=Getvalue,put=Putvalue))
		xmlvalue value;
	xmlvalue Getvalue()
	{
		if (m_xmlnode!=NULL) return xmlvalue(m_xmlnode->text);
		return xmlvalue();
	}
	void Putvalue(xmlvalue newVal)
	{
		if (m_xmlnode!=NULL) m_xmlnode->text = newVal.value;
	}


	
private:
	MSXML2::IXMLDOMNodePtr m_xmlnode;
};

class xmlnodelist
{
public:
	xmlnodelist(MSXML2::IXMLDOMNodeListPtr source)
	{
		m_xmlnodelist = source;
	}
	void operator=(MSXML2::IXMLDOMNodeListPtr source)
	{
		m_xmlnodelist = source;
	}

	int length()
	{
		if (m_xmlnodelist!=NULL) return m_xmlnodelist->length;
		else return 0;
	}

	xmlnode operator[] (int index)
	{
		if (m_xmlnodelist!=NULL) return m_xmlnodelist->item[index];
		else return NULL;
	}

private:
	MSXML2::IXMLDOMNodeListPtr m_xmlnodelist;
};

Open in new window

 

1. Example usage


In order to use the classes you need only to include the above heade.
Sample usage might look like this:
#include "stdafx.h"

#include "xml.h"

int _tmain(int argc, _TCHAR* argv[])
{
	xmldocument doc;
	doc.load("c:\\inventory.xml");
	
	// Cast to node
	xmlnode root(doc);

	// Retrievers
	xmlnode magazine = doc["magazine"];
	magazine = root["magazine"];

	xmlnodelist books = doc("book");
	books = root("book");

	// Iteraring and getting value
	for (int i = 0; i < books.length(); i++)
	{
		std::string firstname = books[i]["author"]["first-name"].value;
		std::wstring lastname = books[i]["author"]["last-name"].value;
		int price = books[i]["price"].value;
	}

	doc.save("c:\\inventory.xml");
	return 0;
}

Open in new window


2. Class members


The header contains tree classes:
class xmldocument;
class xmlnode;
class xmlnodelist;

xmldocument - represents the document
xmlnode - represents single node
xmlnodelist - represents a list of nodes

xmldocument members:
load - loads a document from file or XML string
save - saves a document to a file
operator[] - extracts single child node
operator() - performs XPATH query and returns list of nodes

xmlnode members:
operator[] - extracts single child node
operator() - performs XPATH query and returns list of nodes
value - this is the value property that has __declspec(property) declared for it, this is Microsoft specific technique that allows to deglare getter and setter for a property. This property returns the inner text of the node in form of xmlvalue struct that has automatic cast operators to any native type.

xmlnodelist members:
length() - returns the length of the list (number of nodes)
operator[] - get the n'th node from the list

3. Conclusion


So there were two interesting points in this implementation:
The usage of __declspec(property)  that allowed me to declare a "property" with get and set accessors and the different operators overloading technique. You are welcome to experiment on the code and extend it further to meet your needs, I hope it gives a good starting point.
1
Comment
Author:SunnyDark
  • 2
4 Comments
 
LVL 33

Expert Comment

by:pgnatyuk
std::string firstname = books[i]["author"]["first-name"].value;

Do you think this code is the C++ style?
It's not a complain. It is nice. It is great from the theoretical point of view.
But from the practical point of view, I think, it's better to use C# than overload C++ code with such tricks. Probably, it was not very convinient to debug such code?
It is a good way to "hide" the implementation.
0
 

Expert Comment

by:SimonNaus
could you show me the .xml document you used for this example? it would really help me understand what is going on inside the data-receival loop
0
 
LVL 8

Author Comment

by:SunnyDark
Since this was written a while ago... I don't have an access to the data already, however any sample XML could be used, like the sample Microsoft XML used in their examples:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms762271(v=vs.85).aspx
0
 

Expert Comment

by:SimonNaus
thank you! I got it working now
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Join & Write a Comment

Suggested Articles

The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month