/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# ifndef LIB_XML_CXX_HXX
# define LIB_XML_CXX_HXX
# include <istream>
# include <string>
# include <vector>
# include <map>
# include <memory>
/*! @page limitations Known Limitations
- Templates cannot specify number of sub - elements .
- XML - Comments are not supported .
- Mixed tags and text is not supported . Tags may either contain
other tags only ( type xml : : Node ) or text only ( type
xml : : String ) .
- Unlimited recursion is not possible
( e . g . & ltp & gt ; & ltp & gt ; & ltp & gt ; & lt / p & gt ; & lt / p & gt ; & lt / p & gt ; )
- No check yet for optional and mandatory attributes in xml : : Factory
- Exceptions should be optional , best effort otherwise ( option " strict " ) */
namespace xml {
//============================================================================
class Attributes : public std : : map < std : : string , std : : string > {
public :
class Value : public value_type {
public :
Value ( const std : : string & name ) throw ( ) ;
value_type & operator = ( const std : : string & value ) throw ( ) ;
private :
Value ( ) ; // not implemented
} ;
Attributes ( ) throw ( ) ;
Attributes ( const std : : string & empty ) throw ( ) ;
Attributes & operator < < ( const value_type & v ) throw ( ) ;
Attributes & operator < < ( const std : : string & key ) throw ( ) ;
Attributes & operator = ( const std : : string & value ) throw ( ) ;
private :
iterator _active ;
} ;
typedef Attributes : : Value Attr ;
enum NodeType { START , END , EMPTY , SPECIAL } ;
struct Tag {
std : : string name ;
NodeType type ;
std : : string text ;
Attributes attributes ;
std : : string special ;
} ;
const bool mandatory = true ;
const bool optional = false ;
//================================================================= EXCEPTIONS
class Node ;
class Factory ;
//----------------------------------------------------------------------------
class exception : public std : : exception {
public :
exception ( std : : string reason , const Node & t ) throw ( ) ;
~ exception ( ) throw ( ) ;
const char * what ( ) const throw ( ) ;
private :
std : : string _what ;
Node * _node ;
} ;
//----------------------------------------------------------------------------
class no_parent : public exception {
public :
no_parent ( const Node & t ) throw ( ) : exception ( " node has no parent " , t ) { }
} ;
//----------------------------------------------------------------------------
class tag_expected : public exception {
public :
tag_expected ( const Node & t , const std : : string & txt ) throw ( ) :
exception ( " tag ('<') expected, text not allowed \n text: " + txt , t ) { }
} ;
//----------------------------------------------------------------------------
class type_mismatch : public exception {
public :
type_mismatch ( const Node & t , const std : : string & txt ,
const std : : string & comment ) throw ( ) :
exception ( " wrong type, text contains mismatching character \n " + comment
+ " \n text: " + txt , t ) { }
} ;
//----------------------------------------------------------------------------
class access_error : public exception {
public :
access_error ( const Node & t , const std : : string & name ) throw ( ) ;
~ access_error ( ) throw ( ) { }
const char * what ( ) const throw ( ) ;
private :
std : : string _name ;
} ;
//----------------------------------------------------------------------------
class out_of_range : public exception {
public :
out_of_range ( const Node & t , size_t pos ) throw ( ) ;
~ out_of_range ( ) throw ( ) { }
const char * what ( ) const throw ( ) ;
private :
size_t _pos ;
} ;
//----------------------------------------------------------------------------
class cannot_have_children : public exception {
public :
cannot_have_children ( const Node & parent , const Node & child ) throw ( ) ;
~ cannot_have_children ( ) throw ( ) ;
const char * what ( ) const throw ( ) ;
private :
Node * _child ;
} ;
//----------------------------------------------------------------------------
class stream_error : public exception {
public :
stream_error ( const std : : string & reason , const Node & t ,
std : : istream & is , Tag tag , char c = 0 ) throw ( ) ;
~ stream_error ( ) throw ( ) { }
const char * what ( ) const throw ( ) ;
private :
std : : istream : : streampos _pos ;
Tag _tag ;
char _char ;
} ;
//----------------------------------------------------------------------------
class wrong_end_tag : public stream_error {
public :
wrong_end_tag ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " mismatching end tag " , t , is , tag , c ) {
}
} ;
class missing_end_tag : public stream_error {
public :
missing_end_tag ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " missing end tag, end of file reached " , t , is , tag , c ) {
}
} ;
class empty_stream : public stream_error {
public :
empty_stream ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " no xml tag found, stream is empty " , t , is , tag , c ) {
}
} ;
class wrong_start_tag : public stream_error {
public :
wrong_start_tag ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " start tag does not match expected tag " , t , is , tag , c ) {
}
} ;
class second_slash_in_tag : public stream_error {
public :
second_slash_in_tag ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " a tag may have no more than one slash " , t , is , tag , c ) {
}
} ;
class character_after_slash : public stream_error {
public :
character_after_slash ( const Node & t , std : : istream & is , Tag tag , char c = 0 )
throw ( ) :
stream_error ( " unexpected character after empty-slash " ,
t , is , tag , c ) {
}
} ;
class attributes_in_end_tag : public stream_error {
public :
attributes_in_end_tag ( const Node & t , std : : istream & is , Tag tag )
throw ( ) :
stream_error ( " attributes are not allowed in end tags " , t , is , tag ) {
}
} ;
class attribute_value_not_quoted : public stream_error {
public :
attribute_value_not_quoted ( const Node & t , std : : istream & is , Tag tag ,
char c , std : : string attr ) throw ( ) :
stream_error ( " attribute values must be quoted ( \" ) \n attribute: " + attr ,
t , is , tag , c ) {
}
} ;
class duplicate_attribute : public stream_error {
public :
duplicate_attribute ( const Node & t , std : : istream & is , Tag tag ,
std : : string attr ) throw ( ) :
stream_error ( " attribute duplicated \n attribute: " + attr ,
t , is , tag , 0 ) {
}
} ;
//============================================================================
//----------------------------------------------------------------------------
class Node {
private :
typedef std : : vector < Node * > Contents ;
public :
typedef Contents : : size_type size_type ;
Node ( std : : string name ) throw ( ) ;
Node ( const Node & o ) throw ( ) ;
Node & operator = ( const Node & o ) throw ( ) ;
virtual ~ Node ( ) throw ( ) ;
virtual std : : auto_ptr < Node > clone ( ) const throw ( ) ;
virtual std : : ostream & out ( std : : ostream & o , unsigned int level = 0 ) const
throw ( ) ;
virtual std : : string text ( ) const throw ( ) ;
virtual Node & text ( const std : : string & txt ) throw ( tag_expected ,
type_mismatch ) ;
virtual Node & append ( const Node & o ) throw ( cannot_have_children ) ;
virtual Node & set ( const Attributes & o ) throw ( ) ;
Node & clear ( ) throw ( ) ;
std : : string name ( ) const throw ( ) ;
bool isChild ( ) const throw ( ) ;
Node & parent ( ) const throw ( no_parent ) ;
bool hasAttr ( const std : : string & name ) const throw ( ) ;
Node & attr ( const std : : string & name , bool mandatory ) throw ( ) ;
std : : string attr ( const std : : string & name ) const throw ( ) ;
std : : string & attr ( const std : : string & name ) throw ( ) ;
bool operator ( ) ( const std : : string & child ) const throw ( ) ;
Node & operator < < ( const Node & o ) throw ( cannot_have_children ) ;
Node & operator < < ( const Attributes & o ) throw ( ) ;
//! Get the number of children.
size_type children ( ) const throw ( ) ;
//! Get the n-th child.
const Node & operator [ ] ( size_type child ) const throw ( access_error ) ;
//! Get the n-th child.
Node & operator [ ] ( size_type child ) throw ( access_error ) ;
//! Get the first named child.
const Node & operator [ ] ( const std : : string & child ) const
throw ( access_error ) ;
//! Get the first named child.
Node & operator [ ] ( const std : : string & child ) throw ( access_error ) ;
std : : string operator * ( ) const throw ( ) ;
Node & operator = ( const std : : string & contents ) throw ( tag_expected ,
type_mismatch ) ;
friend std : : ostream & operator < < ( std : : ostream & o , const Node & t ) throw ( ) ;
protected :
Attributes _attributes ;
private :
Node * find ( const std : : string & child ) const throw ( ) ;
virtual std : : auto_ptr < Node > clone ( Node * p ) const throw ( ) ;
Node ( ) ; // not implemented
Contents _contents ;
std : : string _name ;
Node * _parent ;
} ;
//----------------------------------------------------------------------------
class String : public Node {
public :
String ( std : : string name , const std : : string & text = std : : string ( ) ) throw ( ) ;
virtual std : : auto_ptr < Node > clone ( ) const throw ( ) ;
virtual ~ String ( ) throw ( ) { }
virtual std : : string text ( ) const throw ( ) ;
virtual String & text ( const std : : string & txt ) throw ( tag_expected ,
type_mismatch ) ;
virtual std : : ostream & out ( std : : ostream & o , unsigned int level = 0 ) const
throw ( ) ;
virtual String & append ( const Node & o ) throw ( cannot_have_children ) ;
Node & operator = ( const std : : string & contents ) throw ( ) ;
protected :
std : : string _text ;
} ;
//----------------------------------------------------------------------------
class UnsignedInteger : public String {
public :
UnsignedInteger ( std : : string name , unsigned long i = 0 ) throw ( ) ;
virtual std : : auto_ptr < Node > clone ( ) const throw ( ) ;
virtual ~ UnsignedInteger ( ) throw ( ) { }
virtual UnsignedInteger & text ( const std : : string & txt )
throw ( tag_expected , type_mismatch ) ;
unsigned long number ( ) const throw ( ) ;
static unsigned long number ( const Node & node ) throw ( ) ;
} ;
//----------------------------------------------------------------------------
class List : public Node {
} ;
class Factory {
public :
Factory ( const Node & t ) throw ( ) ;
const Node & operator * ( ) const throw ( ) ;
std : : auto_ptr < Node > read ( std : : istream & is )
throw ( wrong_end_tag , wrong_start_tag , tag_expected , type_mismatch ,
second_slash_in_tag , character_after_slash ,
missing_end_tag , attribute_value_not_quoted , access_error ,
empty_stream , duplicate_attribute , attributes_in_end_tag ) ;
private :
friend class stream_error ;
Factory ( ) ; // not implemented
Factory ( const Factory & ) ; // not implemented
bool ws ( char c ) const throw ( ) ;
std : : auto_ptr < Node > read ( std : : istream & is , const Node & position )
throw ( wrong_end_tag , wrong_start_tag , tag_expected , type_mismatch ,
second_slash_in_tag , character_after_slash ,
missing_end_tag ,
attribute_value_not_quoted , access_error , duplicate_attribute ,
attributes_in_end_tag ) ;
Tag tag ( std : : istream & is , const Node & position )
throw ( second_slash_in_tag , character_after_slash ,
missing_end_tag ,
attribute_value_not_quoted , access_error , duplicate_attribute ) ;
std : : auto_ptr < Node > _template ;
} ;
}
# endif