Click here to Skip to main content
15,885,100 members
Articles / Programming Languages / XML

Read and Write application parameters in XML

Rate me:
Please Sign up or sign in to vote.
4.38/5 (33 votes)
30 Jun 20034 min read 1.6M   6.8K   141  
This article provides an easy way to load and save the parameters of an application in XML format.
#ifndef XML_NODE_H
#define XML_NODE_H

#pragma warning (disable : 4786)

#include <string>
#include <vector>
#include <algorithm>

#include "XmlNotify.h"
class ParamIO;

class Element
{
   public:

      Element()
      {
      }

      Element(const std::string &v, const std::string &a):
         value(v),
         attributes(a)
      {
      }

      std::string value;
      std::string attributes;
};

class FindElement
{
public:

   FindElement(const std::string &str) : _searchStr(str)
   {
   }

   bool operator()(const std::pair<std::string, Element> &p) const
   {
      return p.first == _searchStr;
   }

   std::string _searchStr;
};

class FindNode;

class XML_Node
{
	public:

		typedef std::vector<XML_Node>::const_iterator nodes_const_iterator;
		typedef std::vector<XML_Node>::iterator nodes_iterator;

		typedef std::vector< std::pair<std::string, Element > >::iterator elements_iterator;
		typedef std::vector< std::pair<std::string, Element > >::const_iterator elements_const_iterator;

		XML_Node();

		XML_Node(const std::string &name, const std::string &attributes, XML_Node *parent);

		void set(const std::string &name, const std::string &attributes, XML_Node *parent);

		void addElement(const std::string &name, const std::string &value, const std::string &attributes);
		XML_Node *addNode(const std::string &name, const std::string &attributes);

		bool getElement(const std::string &name, std::string &value, std::string &attributes);
		bool setElementValue(const std::string &name, const std::string &value);

		elements_const_iterator beginElements() const;
		elements_const_iterator endElements() const;

		nodes_const_iterator beginNodes() const;
		nodes_const_iterator endNodes() const;

		nodes_iterator beginNodes();
		nodes_iterator endNodes();

		nodes_const_iterator findNode(const std::string &name) const;
		nodes_iterator findNode(const std::string &name);

		const std::string &getName() const;

		template<class T>
		bool extractValue(const std::string &str, T &value) const
		{
         elements_const_iterator it = std::find_if(_elements.begin(), _elements.end(), FindElement(str));
			if(it == endElements())
			{
				return false;
			}

			std::stringstream ist(it->second.value);
			ist >> value;

			return ist.fail()==0;
		}

		// We need a specific method in std::string case so that
		// we can get space-separated words
		bool extractValue(const std::string &str, std::string &value) const;

		XML_Node *getParent();

		void print(std::ostream &os) const;

		void clear();

        bool eraseElement(const std::string &name);
        bool eraseNode(const std::string &name);


		~XML_Node();


	private:

		// In case we have no child node
        std::vector< std::pair<std::string, Element > > _elements;
		std::string _name, _attributes;

		// In case we have child node
		std::vector<XML_Node> _nodes;

		// Parent
		XML_Node* _parent;
};

class XML_Param_Notify : public XmlNotify
{
public:

	XML_Param_Notify();

	virtual ~XML_Param_Notify();

	void clear();

	XML_Node::nodes_iterator top();

	template<class T>
		bool extractValue(std::vector<std::string> strs, T &value) const
	{
		// First we need to find the final node
		std::string paramName = strs.back();
		strs.pop_back();
		XML_Node::nodes_const_iterator res = getNode(strs);
		if(res == static_cast<XML_Node::nodes_const_iterator>(0))
		{
			return false;
		}

		// We found the last node, find the element
		return res->extractValue(paramName, value);
	}

	XML_Node::nodes_const_iterator  getNode(std::vector<std::string> &strs) const;
	XML_Node::nodes_iterator  getNode(std::vector<std::string> &strs);

	template<class T>
	bool	addElement(std::vector<std::string> &strs, T &value)
	{
		// First we need to find the final node
		XML_Node::nodes_iterator end, begin;
		XML_Node::nodes_iterator res, prevRes;
		unsigned int i;

		begin = static_cast<XML_Node::nodes_iterator>(&_node);
		end   = static_cast<XML_Node::nodes_iterator>(&(_node) + 1);
		bool go_out = false;

		res = prevRes = static_cast<XML_Node::nodes_iterator>(0);
		for(i=0; i<strs.size()-1 && go_out==false; i++)
		{
			prevRes = res;

			res = std::find_if(begin, end, FindNode(strs[i]));
			if(res == end)
			{
				// Couldn't find the proper parameter
				go_out = true;
			}
			else
			{
				begin = res->beginNodes();
				end   = res->endNodes();
			}
		}

		// Do we need to create any node?
		if(go_out == true)
		{
			i--;
			// We need to create new nodes
			for(;i<strs.size()-1; i++)
			{
				if(prevRes == static_cast<XML_Node::nodes_iterator>(0))
				{
					// It means the tree is empty
					_node.set(strs[i], std::string(), 0);
					prevRes = static_cast<XML_Node::nodes_iterator>(&(_node));
				}
				else
				{
					prevRes = static_cast<XML_Node::nodes_iterator>(prevRes->addNode(strs[i], std::string()));
				}
			}
		}
		else
		{
			prevRes = res;
		}

		std::stringstream stream;
		stream << value;/* << std::ends; => adds an useless extra character*/

		prevRes->addElement(strs.back(), stream.str(), std::string());

		return true;
	}

   bool compare(const ParamIO &old, std::vector<std::string> &strs) const;

   bool extractSubTree(std::vector<std::string> &strs, ParamIO &subTree) const;

   bool eraseSubTree(std::vector<std::string> &strs);

	void print(std::ostream &os) const;

	// notify methods
	virtual void foundNode( std::string & name, std::string & attributes );
	virtual void endNode( std::string & name, std::string & attributes );

	virtual void foundElement( std::string & name, std::string & value, std::string & attributes );

private:

   bool compareElement(const ParamIO &old, std::vector<std::string> &strs) const;
   bool compareSubTree(const ParamIO &old, std::vector<std::string> &strs) const;

   bool compareAllElements(XML_Node::nodes_const_iterator  it, XML_Node::nodes_const_iterator  itOld) const;
   bool compareAllChildren(XML_Node::nodes_const_iterator  it, XML_Node::nodes_const_iterator  itOld) const;
	
	XML_Node _node;

	XML_Node *_currentNode;
};

// class used by find_if in findSameName method
// Note : we could have avoided the FindSameName class using a std::string
// converter operator for the XML_Node class. But adding such an operator
// for this purpose didn't seem right.

class FindNode
{
public:
   FindNode(const std::string &name):
      _name(name)
   {
   }

   bool operator()(const XML_Node &node)
   {
      return _name.compare(node.getName()) == 0?true:false;
   }

   std::string _name;
};


#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 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


Written By
Web Developer
China China
I've been living & working in Tokyo since 2000 . I'm currently working in Gentech Corp. (www.gen.co.jp), developing computer vision applications, especially in the field of face detection.

I've been interested in C++ for quite a while and recently discovered Ruby.

My hobbies are trekking, japanese food, yoga & onsens.

Comments and Discussions