Click here to Skip to main content
15,889,808 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.7K   886   38  
Writing multiple enumerated configuration entries.
#include "C:\tmp\Tool Classes\ParamIO\ParamIO.h"
#include <cassert>
#include <stdarg.h>

///////////////////////////////////////////////////////////////////////////////
//Wrapper around ParamIo by TBW
///////////////////////////////////////////////////////////////////////////////
enum VAL_TYPE
{
	VALUE_UNKNOW = -1,
	VAIUE_INT,// "int"
	VAIUE_STRING,//"string"
	VALUE_FLOAT,//"float"
	VALUE_BOOL,//"bool"
	VALUE_HEX//"hexa"
};

///////////////////////////////////////////////////
//TypeDefine : Definition of Types, and Type Checking of Strings
///////////////////////////////////////////////////
class TypeDefine
{
	typedef std::vector< std::pair<std::string, VAL_TYPE > >::iterator type_iterator;
	class FindType
	{
		public:
			FindType( std::string strToken ) : m_strToken(strToken){ m_valType = VALUE_UNKNOW; }
			FindType( VAL_TYPE valType ){ m_valType = valType; }
			bool operator()(std::pair<std::string, VAL_TYPE> &p) const
			{
				if(m_valType == VALUE_UNKNOW )
				{
					if( m_strToken.find( p.first ) != std::string::npos )
						return true;
				}
				else
				{
					return p.second == m_valType;
				}
				return false;
			}
			std::string m_strToken;
			VAL_TYPE m_valType;
	};
public:
	TypeDefine()
	{
		m_vKnownTypes.reserve( 5 );
		m_vKnownTypes.push_back( std::make_pair( std::string("int"), VAIUE_INT ) );
		m_vKnownTypes.push_back( std::make_pair( std::string("string"), VAIUE_STRING ) );
		m_vKnownTypes.push_back( std::make_pair( std::string("float"), VALUE_FLOAT ) );
		m_vKnownTypes.push_back( std::make_pair( std::string("bool"), VALUE_BOOL ) );
		m_vKnownTypes.push_back( std::make_pair( std::string("hex"), VALUE_HEX ) );
	}
	VAL_TYPE GetType( std::string& strToken, std::string& strValName )
	{
		type_iterator iterFound = std::find_if( m_vKnownTypes.begin(), m_vKnownTypes.end(), FindType(strToken) );
		if( iterFound != m_vKnownTypes.end() )
		{
			std::string::size_type TypeEnd = strToken.find( iterFound->first );
			std::string::size_type NameEnd = strToken.find( "=" );
			size_t iNameStart = iterFound->first.size();
			size_t iNameEnd = NameEnd - iNameStart - 1;
			strValName = strToken.substr( iNameStart, iNameEnd );
			return iterFound->second;
		}
		else
		{
			strValName = strToken;
		}
		return VALUE_UNKNOW;//no match
	}
	std::string GetValTypePrefix( VAL_TYPE valType )
	{
		type_iterator iterFound = std::find_if( m_vKnownTypes.begin(), m_vKnownTypes.end(), FindType(valType) );
		if( iterFound != m_vKnownTypes.end() )
			return iterFound->first;
		return "";
	}
private:
	std::vector< std::pair<std::string, VAL_TYPE > > m_vKnownTypes;
};

///////////////////////////////////////////////////
//Attribute : behaviour of a single Attribute
///////////////////////////////////////////////////
class Attribute
{
	public:	Attribute( std::string& strTokenString );
	template<class T>bool GetValue( T&value )
	{
		std::stringstream ist(m_strAttributeValue);
		if( m_ValType == VALUE_HEX )
			ist >> std::hex >>value;//TBW : maybe shall be reomved
		else
			ist >> value;
		return true;
	}
	bool operator==( const std::string& strAttributeName ) const
	{
		return m_strAttributeName == strAttributeName;
	}
	private:
		std::string m_strAttributeName;
		std::string m_strAttributeValue;
		VAL_TYPE m_ValType;
};

//////////////////////////////////////////////////////////////////////////////////////
//ConfigValue : behaviour of a whole Key == ConfigValue - can have multiple Attributes
//////////////////////////////////////////////////////////////////////////////////////
class ConfigValue
{
	typedef std::vector< Attribute >::iterator attribute_iterator;
	class FindAttribute
	{
		public:
			FindAttribute( std::string strAttribName ) : m_strCmpName(strAttribName){}
			bool operator()(Attribute& aAttrib ) const
			{
				return aAttrib == m_strCmpName;
			}	
			std::string m_strCmpName;
	};
	friend class CfgValueCont;
private:
	ConfigValue( std::string strKeyName, const char* strAttributeString );//parsing of the Attribute string
	ConfigValue( std::string strKeyName, Element& aEl );
	void ParesAttributeString( std::string& strAttributeString );
	template<class T>bool GetValue( int iIndex, T&value, T& defaultVal )//for easy enumerating through loaded values
	{
		if( (unsigned int)iIndex < m_vFoundValues.size() )
			return m_vFoundValues[iIndex].GetValue( value );
		value = defaultVal;		
		return false;
	}
	template<class T>bool GetValue( std::string& strName, T& value, T& defaultVal )// true search -> by Name - gets the first match if same names in one branch
	{
		attribute_iterator iterFound = std::find_if( m_vFoundValues.begin(), m_vFoundValues.end(), FindAttribute(strName) );
		if( iterFound != m_vFoundValues.end() )
		{
			(*iterFound).GetValue( value );
		}
		else
		{
			value = defaultVal;
			return false;
		}
		return false;
	}
	std::vector< Attribute > m_vFoundValues;
	std::string strKeyName;		
};

//////////////////////////////////////////////////////////////////////////////////////
//CfgValueCont : container for ConfigValues
//////////////////////////////////////////////////////////////////////////////////////
class CfgValueCont
{
	friend class XmlConfig;
private:
	CfgValueCont();
	void AddValue( std::string strKeyName, char* strAttributeString );
	void AddValue( std::string strKeyName, Element& aEl );
	size_t size(void){ return m_vReadCnfgValue.size(); }
	void clear(void){ m_vReadCnfgValue.clear(); }
	template<class T>bool GetValue( int iIndex, int iAttributeIndex, T&value, T& defaultVal )//for easy enumerating through loaded values
	{
		return m_vReadCnfgValue[iIndex].GetValue( iAttributeIndex, value, defaultVal );
	}
		
	template<class T>bool GetValue( int iIndex, std::string& strValueName, T&value, T& defaultVal )// true search -> by Name
	{
		assert(iIndex < m_vReadCnfgValue.size() );
		return m_vReadCnfgValue[iIndex].GetValue( strValueName, value, defaultVal );
	}
	std::vector< ConfigValue > m_vReadCnfgValue;
};

//////////////////////////////////////////////////////////////////////////////////////
//XmlConfig : main Wrapper Class around ParamIO
//////////////////////////////////////////////////////////////////////////////////////
class XmlConfig
{
public:
	XmlConfig();
	XmlConfig( const char* filename );
	void DefaultInit(void);//some default Initialisation stuff
	virtual ~XmlConfig();	
	template<class T>bool read(const char *str, T &value, T& defaultVal) const
	{
		return m_ParamIO.read( str, value, defaultVal );
	}
	template<class T>bool write(const char *str, T& value)
	{
		return m_ParamIO.write( str, value );
	}
   	void readFile(const char *filename);
	void writeFile(const char *filename) const;
	void readStream(std::istream &is);
	void readBuffer( char* pstrBuffer );
	void writeStream(std::ostream &os) const;
	bool erase( char* pstrSubKey );
	
	int erase( char* pstrSubKey, char* pstrAttributeMatchKey, ... );
	ParamIO& GetParamIoRef(void){ return m_ParamIO; };
	bool ReadSubtree( const char *strSubTree );
	size_t ReadCurrentTree( void );//reads the current active Subtree
	size_t GetReadValueCount(void){ return m_RedCnfgValues.size(); }
	size_t hasSubNodes( char* pstrSubKey, std::string& strNodeName );//has the current extracted Tree a Sub - Node ??
	bool enterSubTree( std::string& strSubTree );//enters the Subtree named in strSubTree, acoording to current Position
	bool leaveSubTree(void);//leaves the current Subtree
	
	template<class T>int AddAttributes( char* pstrKey, VAL_TYPE valTypeToAdd, char* strAttributeName, T& Attribute, char* pstrAttributeMatchKey, ...  )
	{
		//Build the Search Kriteria vector
		va_list marker;
		va_start( marker, pstrAttributeMatchKey );
		std::vector<string> vKeyString;
		while( pstrAttributeMatchKey != 0 )
		{
			vKeyString.push_back( std::string( pstrAttributeMatchKey ) );
			pstrAttributeMatchKey = va_arg( marker, char* );  
		}
		va_end( marker );
		std::stringstream ist;
		ist << Attribute;

		std::string strAtributeString = " ";//always start with a preceding space to avoid anger...
		strAtributeString += XmlConfig::m_TypeDefinition.GetValTypePrefix( valTypeToAdd );
		strAtributeString += string(strAttributeName);
		strAtributeString += " = ";
		strAtributeString += '"';
		strAtributeString += ist.str();
		strAtributeString += '"';		
		return m_ParamIO.addAttributes( pstrKey, vKeyString, strAtributeString );
	}
	int AddAttributeString( char* pstrKey, char* pstrAttributeString, char* pstrAttributeMatchKey, ... );
	int RemoveAttributes( char* pstrKey, char* strAttributeName, char* pstrAttributeMatchKey, ...  );
	template<class T>bool GetValue( int iIndex, int iAttributeIndex, T&value, T defaultVal )//for easy enumerating through loaded values
	{
		return m_RedCnfgValues.GetValue( iIndex, iAttributeIndex, value, defaultVal );
	}
	template<class T>bool GetValue( int iIndex, std::string& strName, T&value, T defaultVal )//for easy enumerating through loaded values
	{
		return m_RedCnfgValues.GetValue( iIndex, strName, value, defaultVal );
	}
	static TypeDefine m_TypeDefinition;//The Definition Tabel of Known Types
	void writeCompleteStream( std::ostream &os ) const;//writes a complete outputstream including the header
	void SetHeader( char* pstrXmlVersion, char* pstrEncoding );
	static std::string CheckStringForLineBreaks( const char* pstrInput );//inserts a \r\n after avery </> Tag, if there is none
	static void RemoveString( std::string& strInput, std::string& strSignToRemove );//removes all occurences of strSignToRemove in strInput
private:
	std::string m_strXmlVersion;
	std::string m_strEncoding;
	void WriteHeader( std::ostream &os ) const;//Writes the XML - File - Header : e.g.: <?xml version="1.0" encoding="ISO-8859-1"?>
	size_t ExtractElements( XML_Node& aNode );
	size_t ExtractNode( XML_Node& aNode );
	ParamIO m_ParamIO;
	ParamIO m_ActiveTree;
	CfgValueCont m_RedCnfgValues;	
};

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