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.