Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C++

A STL based XML Config Tool

Rate me:
Please Sign up or sign in to vote.
3.19/5 (9 votes)
19 Jun 20051 min read 69.4K   886   38  
Writing multiple enumerated configuration entries.
#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;
	  //TBW : Added ==
	  bool operator==( const Element& aEl )const
	  {
		if( aEl.value == value && aEl.attributes == attributes )
			return true;
		else
			return false;
	  }
};

//TBW : added to look for Elements specific to their Atttributes
class FindElementByAttribute
{
public:
	FindElementByAttribute( const std::string strName, const std::vector<std::string>& vTokensToFindInAttributes ) : m_strName(strName), m_vAttributeTokensToFind(vTokensToFindInAttributes){}
	bool operator()(const std::pair<std::string, Element> &p)
	{
		if( p.first == m_strName )
		{
			if(m_vAttributeTokensToFind.empty())//ready if nothing else to check
				return true;
			size_t iFoundPos = 0;// to not find two times the same again
			std::vector<std::string>::iterator itBeg = (const std::vector<std::string>::iterator)m_vAttributeTokensToFind.begin();
			std::vector<std::string>::iterator itEnd = (const std::vector<std::string>::iterator)m_vAttributeTokensToFind.end();
			std::string strAttributes = p.second.attributes;
			for( std::vector<std::string>::iterator iter = itBeg; iter != itEnd; iter++ )
			{
				if( (iFoundPos = strAttributes.find( *iter ) )== std::string::npos )
					return false;
				else
				{
					//eliminate the found String to not find it again
					strAttributes.erase( iFoundPos, (*iter).size() );
				}
			}
			return true;
		}
		return false;
	}
	std::string m_strName;
	std::vector<std::string> m_vAttributeTokensToFind;
};

class FindElement//TBW : changed ->only equal, if whole Element matches
{
public:

	FindElement( const std::string strName, const Element aElem ) : m_strName(strName), m_Elem(aElem)
	{	
		m_bFullCompare = true;
	}
	FindElement( std::string strName) : m_strName(strName)
	{
		m_bFullCompare = false;
	}
	bool operator()(const std::pair<std::string, Element> &p) const
	{
		if(!m_bFullCompare)
		{
		return p.first == m_strName;
		}
		else
		{
			return ((p.first == m_strName) && (m_Elem == p.second ));
		}
		return false;
	}
	bool m_bFullCompare;//shall both be compared?
	std::string m_strName;
	Element m_Elem;
};

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);

		int removeAttributesFromElements(const std::string &name, std::vector<std::string>& vTokensToFindInAttributes, const std::string &AttributesToRemove );//removes Attributes from Elements matching the specified Key in vector
		int addAttributesToElements(const std::string &name, std::vector<std::string>& vTokensToFindInAttributes, const std::string &AttributesToAdd );//adds Attributes to Elements matching the specified Key in vector

		
		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 beginNodesConst() const;
		nodes_const_iterator endNodesConst() 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);
		int eraseElements( const std::string &name, std::vector<std::string>& vTokensToFindInAttributes );//erases all Elements matching the attribute - strings in vector
		bool eraseNode(const std::string &name);


		~XML_Node();
		//Added by TBW for Debug Help
		size_t getElementCount(void) const{ return _elements.size(); }
		size_t getNodeCount(void) const{ return _nodes.size(); }


	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 = getNodeConst(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  getNodeConst( 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 prevRes = GetAddIterator(strs);
		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);
//TBW : added
	XML_Node::nodes_iterator GetAddIterator(std::vector<std::string> &strs);
	int eraseElement( std::vector<std::string> &vNodes, std::vector<std::string>& vTokensToFindInAttributes );//erasese all elements matching name and Attribute strings in vector
	int addElementAttributes( std::vector<std::string> &vNodes, std::vector<std::string>& vTokensToFindInAttributes, const std::string& strAttributeVal );
	int removeElementAttributes( std::vector<std::string> &vNodes, std::vector<std::string>& vTokensToFindInAttributes, const std::string& strAttributeVal );
	bool addElement( std::vector<std::string> &strs, const char* strAttributeString );//creates an Element setting its Attributes
	int addAttributeString( std::vector<std::string> &vNodes, std::vector<std::string>& vTokensToFindInAttributes, const char* strAttributeString );//sets the complete Attribute String -> overriding the old one


	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
Software Developer
Germany Germany
Studying and having a degree of medical engineering, but decided to work as a software developer writing medical applications for image processing.

Comments and Discussions