RapidXml Parsing Wrapper

Hey All,

Want to share with you all a piece of code that i wrote. Recently i was working on a c++ application where some xml parsing was required, i you search on google for C++ xml parser their are lot of open source parser that is available but my favorite was RapidXml. Rapid Xml is much faster than others. You can check the performance comparison here . So if you need a xml parser in c++ Rapid Xml is strongly recommended.

The piece of code that i wish to share is wrapper over rapid xml to read the data from xml a bit easier.

Following is the code

RapidXmlWrapper.h

#pragma once
#include <string>
#include <map>
#include "rapidxml-1.13\rapidxml.hpp"

using namespace std;

class RapidXmlWrapper
{
public:
	RapidXmlWrapper(){}
public:
	static rapidxml::xml_node<>* getNodeByName(const string& nodeName, rapidxml::xml_node<>* parentNode);
	static rapidxml::xml_node<>* getNodeByNameAndAttribute(const string& nodeName, const string& attrName, const string& attribValue, rapidxml::xml_node<>* node);
	static string getAttributeValue(const std::string& attributeName, rapidxml::xml_node<>* node);
	static map<string, string> getParamMapsFromNode(rapidxml::xml_node<>* node);
};


RapidXmlWrapper.cpp


#include "RapidXmlWrapper.h"
#include <sstream>

/**
* Gets a node object from given node name and parent node.
*/
rapidxml::xml_node<>* RapidXmlWrapper::getNodeByName(const string& nodeName, rapidxml::xml_node<>* parentNode)
{
	if(parentNode == NULL)
	{
		// parent node must not be null
		ostringstream errorBuilder;
		errorBuilder << " parentNode object should not be null: ";
		throw runtime_error(errorBuilder.str());
	}

   rapidxml::xml_node<>* node = parentNode->first_node();

   while(node != NULL)
   {
      if(node->name() == nodeName)
      {
         return node;
      }

      node = node->next_sibling(); 
   }
   return NULL;
}

/**
* Get node object from given node name, attribName, attribValue and parent node.
*/
rapidxml::xml_node<>* RapidXmlWrapper::getNodeByNameAndAttribute(const string& nodeName, const string& attrName, const string& attribValue, rapidxml::xml_node<>* parentNode)
{
	if(parentNode == NULL)
	{
		// parent node must not be null
		ostringstream errorBuilder;
		errorBuilder << " parentNode object should not be null: ";
		throw runtime_error(errorBuilder.str());
	}

	rapidxml::xml_attribute<>* attr = parentNode->first_attribute(attrName.c_str());
	if( (attr != NULL) && (attr->value() == attribValue) && (parentNode->name() == nodeName))
	{
		return parentNode;
	}

	rapidxml::xml_node<>* node = parentNode->first_node();

	while(node != NULL)
	{
		if(node->name() == nodeName)
		{
			// If attribute name and value empty then return node
			if(attrName.empty() || attribValue.empty())
			{
				return node;
			}
			else
			{
				rapidxml::xml_attribute<>* attr = node->first_attribute(attrName.c_str());
				if( (attr != NULL) && (attr->value() == attribValue) )
				{
					return node;
				}
			}
		}
		node = node->next_sibling(); 
	}
	return NULL;
}

/**
* Get attribute value from given attribute name and given node object.
*/
string RapidXmlWrapper::getAttributeValue(const std::string& attributeName, rapidxml::xml_node<>* node)
{
	string attributValue = "";

	if(node == NULL)
	{
		// throw This node must be initialized
		ostringstream errorBuilder;
		errorBuilder << "node object should not be null,for attribute name:" + string(attributeName);
		throw runtime_error(errorBuilder.str());
	}

	rapidxml::xml_attribute<>* attribute = node->first_attribute(attributeName.c_str());
	if(NULL == attribute)
	{
		ostringstream errorBuilder;
		errorBuilder << "Attribute not found, for attribute name:" + attributeName;
		throw runtime_error(errorBuilder.str());
	}
	attributValue = attribute->value();
	return attributValue;
}

/**
* Get map of string, string i.e. key value pair from given node object.
* ex: <Employees>
		<Employee Name="John" Age="30"/>
		<Employee Name="Harry" Age="27"/>
		<Employee Name="Kate" Age="29"/>
*     </Employees> 
*    
*    Method will result the map of Employees with Name and age as key value pairs 
*/
map<string, string> RapidXmlWrapper::getParamMapsFromNode(rapidxml::xml_node<>* node)
{
   map<string, string> paramsMap;

   if(node == NULL) 
   {
      // This node must be initialized
	   ostringstream errorBuilder;
	   errorBuilder << "node object should not be null";
	   throw runtime_error(errorBuilder.str());
   }


   for(rapidxml::xml_node<>* currNode = node->first_node(); currNode != NULL; currNode = currNode->next_sibling())
   {
      string nodeName = currNode->name();
      rapidxml::xml_attribute<>* nameAttr = currNode->first_attribute("Name");
      rapidxml::xml_attribute<>* valueAttr = currNode->first_attribute("Age");
      if(nodeName == "Employee" && nameAttr != NULL && valueAttr != NULL)
      {
         paramsMap.insert(pair<string, string>(nameAttr->value(), valueAttr->value()));
      }
   }

   return paramsMap;
}

Usage of the Wrapper class is very simple, consider the following xml as sample

<?xml version="1.0" encoding="utf-8"?>
<Company>
  <Employees>
    <Employee Name="John" Age="30"/>
    <Employee Name="Harry" Age="27"/>
    <Employee Name="Kate" Age="29"/>
  </Employees>
  <Departments>
    <Department Name="Sales" TeamSize="4"/>
    <Department Name="Marketing" TeamSize="10"/>
    <Department Name="Developemnt" Head="kapil" TeamSize="5"/>
    <Department Name="Testing" Head="John">
    </Department>
  </Departments>
</Company>
 

Following is the usage:

		rapidxml::xml_document doc;
		string fileContents = getFileContents("SampleXmlFile.xml");
		doc.parse((char*)fileContents.c_str());

		//Extract employee Map
		rapidxml::xml_node* node = RapidXmlWrapper::getNodeByName("Employees",doc.first_node());
		map employeeList = RapidXmlWrapper::getParamMapsFromNode(node);


		//Extract Head of the Development Department
		rapidxml::xml_node* pNode = RapidXmlWrapper::getNodeByName("Departments",doc.first_node());
		rapidxml::xml_node* dNode = RapidXmlWrapper::getNodeByNameAndAttribute("Department","Name","Developemnt",pNode);
		string departmentHead = RapidXmlWrapper::getAttributeValue("Head",dNode);

License
This project is licensed under the WTFPL Public License

Download

Attached is the visual studio solution describing usage and functionality, download it from here

Thanks For reading the post and please post your valuable comments and suggestion for improvement.

This entry was posted in c++, Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s