/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# include <xml-cxx/xml.hxx>
# include <iostream>
# include <sstream>
# include <cstdlib>
# include <iomanip>
class MethodTrace {
public :
MethodTrace ( const void * addr , const std : : string & name ) throw ( ) :
_addr ( addr ) , _name ( name ) {
std : : clog < < std : : hex < < std : : setw ( 15 ) < < _addr < < " : "
< < std : : dec < < std : : setw ( 2 + _level )
< < std : : setfill ( ' ' ) < < " \\ " < < _name < < std : : endl ;
+ + _level ;
}
~ MethodTrace ( ) throw ( ) {
- - _level ;
std : : clog < < std : : hex < < std : : setw ( 15 ) < < _addr < < " : " < < std : : dec
< < std : : setw ( 2 + _level ) < < std : : setfill ( ' ' )
< < " / " < < _name < < std : : endl ;
}
private :
const void * _addr ;
const std : : string _name ;
static unsigned int _level ;
} ;
unsigned int MethodTrace : : _level ( 0 ) ;
# define TRACE MethodTrace XXX_METHOD(this, __PRETTY_FUNCTION__)
# define LOG(X) std::clog<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl
namespace xml {
//============================================================================
Attributes : : Value : : Value ( const std : : string & name ) throw ( ) :
Attributes : : value_type ( name , std : : string ( ) ) {
}
Attributes : : value_type & Attributes : : Value : : operator = ( const std : : string & value )
throw ( ) {
second = value ;
return * this ;
}
Attributes : : Attributes ( ) throw ( ) : _active ( end ( ) ) { }
Attributes : : Attributes ( const std : : string & empty ) throw ( ) {
_active = insert ( Value ( empty ) ) . first ;
}
Attributes & Attributes : : operator < < ( const value_type & v ) throw ( ) {
_active = insert ( v ) . first ;
return * this ;
}
Attributes & Attributes : : operator < < ( const std : : string & key ) throw ( ) {
_active = insert ( Value ( key ) ) . first ;
return * this ;
}
Attributes & Attributes : : operator = ( const std : : string & value ) throw ( ) {
if ( _active = = end ( ) ) return * this ;
_active - > second = value ;
_active = end ( ) ;
return * this ;
}
//================================================================= EXCEPTIONS
//----------------------------------------------------------------------------
exception : : exception ( std : : string reason , const Node & t ) throw ( ) :
_what ( reason ) , _node ( t . clone ( ) . release ( ) ) {
}
exception : : ~ exception ( ) throw ( ) {
delete _node ;
}
const char * exception : : what ( ) const throw ( ) {
static std : : string w ;
if ( ! w . size ( ) ) {
if ( _node )
if ( _node - > isChild ( ) )
w = _what + " \n tag: " + _node - > name ( ) + " \n parent: " + _node - > parent ( ) . name ( ) ;
else
w = _what + " \n tag: " + _node - > name ( ) + " (root element) " ;
else
w = _what ;
}
return w . c_str ( ) ;
}
//----------------------------------------------------------------------------
access_error : : access_error ( const Node & t , const std : : string & name ) throw ( ) :
exception ( " child not available " , t ) , _name ( name ) {
}
const char * access_error : : what ( ) const throw ( ) {
static std : : string w ;
if ( ! w . size ( ) ) w = std : : string ( exception : : what ( ) ) + " \n child name: " + _name ;
return w . c_str ( ) ;
}
//----------------------------------------------------------------------------
out_of_range : : out_of_range ( const Node & t , size_t pos ) throw ( ) :
exception ( " child not available " , t ) , _pos ( pos ) {
}
const char * out_of_range : : what ( ) const throw ( ) {
static std : : stringstream w ;
if ( ! w . str ( ) . size ( ) ) w < < exception : : what ( ) < < " \n child number: " < < _pos ;
return w . str ( ) . c_str ( ) ;
}
//----------------------------------------------------------------------------
cannot_have_children : : cannot_have_children ( const Node & parent ,
const Node & child ) throw ( ) :
exception ( " node does not accept child nodes " , parent ) ,
_child ( child . clone ( ) . release ( ) ) {
}
cannot_have_children : : ~ cannot_have_children ( ) throw ( ) {
delete _child ;
}
const char * cannot_have_children : : what ( ) const throw ( ) {
static std : : string w ;
if ( ! w . size ( ) )
w = std : : string ( exception : : what ( ) ) + " \n child name: " + _child - > name ( ) ;
return w . c_str ( ) ;
}
//----------------------------------------------------------------------------
stream_error : : stream_error ( const std : : string & reason , const Node & t ,
std : : istream & is , Tag tag , char c ) throw ( ) :
exception ( reason , t ) , _pos ( is . tellg ( ) ) , _tag ( tag ) , _char ( c ) {
}
const char * stream_error : : what ( ) const throw ( ) {
static std : : string w ;
if ( ! w . size ( ) ) {
std : : stringstream ss ;
ss < < exception : : what ( )
< < " \n position in stream: " < < _pos ;
if ( _char )
ss < < " \n actual character: " < < ( _char > 31 ? _char : ' ? ' )
< < " (ascii= " < < ( int ) _char < < " ) " ;
ss < < " \n tag type: " < < ( _tag . type = = START ? " START "
: ( _tag . type = = END ? " END "
: ( _tag . type = = EMPTY ? " EMPTY "
: " ???? <UNKNOWN> " ) ) ) ;
if ( _tag . name . size ( ) ) ss < < " \n node name read: " < < _tag . name ;
if ( _tag . text . size ( ) ) ss < < " \n contained text: " < < _tag . text ;
w = ss . str ( ) ;
}
return w . c_str ( ) ;
}
//============================================================================
//----------------------------------------------------------------------------
Node : : Node ( std : : string name ) throw ( ) :
_name ( name ) , _parent ( 0 ) {
}
Node : : Node ( const Node & o ) throw ( ) :
_attributes ( o . _attributes ) , _name ( o . name ( ) ) , _parent ( 0 ) {
for ( Contents : : const_iterator it ( o . _contents . begin ( ) ) ;
it ! = o . _contents . end ( ) ; + + it )
_contents . push_back ( ( * it ) - > clone ( this ) . release ( ) ) ;
}
Node & Node : : operator = ( const Node & o ) throw ( ) {
_attributes = o . _attributes ;
_name = o . name ( ) ;
_parent = 0 ;
for ( Contents : : const_iterator it ( o . _contents . begin ( ) ) ;
it ! = o . _contents . end ( ) ; + + it )
_contents . push_back ( ( * it ) - > clone ( this ) . release ( ) ) ;
}
Node : : ~ Node ( ) throw ( ) {
clear ( ) ;
}
std : : auto_ptr < Node > Node : : clone ( ) const throw ( ) {
std : : auto_ptr < Node > res ( new Node ( * this ) ) ;
res - > _parent = 0 ;
return res ;
}
std : : ostream & Node : : out ( std : : ostream & o , unsigned int level ) const throw ( ) {
if ( _contents . size ( ) ) {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < ' > ' < < std : : endl ;
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
( * it ) - > out ( o , level + 1 ) < < std : : endl ;
o < < std : : string ( level , ' \t ' ) < < " </ " < < name ( ) < < ' > ' ;
} else {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < " /> " ;
}
return o ;
}
std : : string Node : : text ( ) const throw ( ) {
std : : string s ;
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
s + = * * * it ;
return s ;
}
Node & Node : : text ( const std : : string & txt ) throw ( tag_expected , type_mismatch ) {
throw tag_expected ( * this , txt ) ;
}
Node & Node : : append ( const Node & o ) throw ( cannot_have_children ) {
_contents . push_back ( o . clone ( this ) . release ( ) ) ;
return * this ;
}
Node & Node : : set ( const Attributes & o ) throw ( ) {
_attributes . insert ( o . begin ( ) , o . end ( ) ) ;
return * this ;
}
Node & Node : : clear ( ) throw ( ) {
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
delete * it ;
_contents . clear ( ) ;
_attributes . clear ( ) ;
return * this ;
}
std : : string Node : : name ( ) const throw ( ) {
return _name ;
}
bool Node : : isChild ( ) const throw ( ) {
return _parent ;
}
Node & Node : : parent ( ) const throw ( no_parent ) {
if ( ! _parent ) throw no_parent ( * this ) ;
return * _parent ;
}
bool Node : : hasAttr ( const std : : string & name ) const throw ( ) {
return _attributes . find ( name ) ! = _attributes . end ( ) ;
}
Node & Node : : attr ( const std : : string & name , bool mandatory ) throw ( ) {
_attributes [ name ] = mandatory ? " mandatory " : " optional " ;
return * this ;
}
std : : string Node : : attr ( const std : : string & name ) const throw ( ) {
Attributes : : const_iterator it ( _attributes . find ( name ) ) ;
if ( it ! = _attributes . end ( ) ) return it - > second ;
return std : : string ( ) ;
}
std : : string & Node : : attr ( const std : : string & name ) throw ( ) {
return _attributes [ name ] ;
}
bool Node : : operator ( ) ( const std : : string & child ) const throw ( ) {
return find ( child ) ;
}
Node & Node : : operator < < ( const Node & o ) throw ( cannot_have_children ) {
return append ( o ) ;
}
Node & Node : : operator < < ( const Attributes & o ) throw ( ) {
return set ( o ) ;
}
Node : : size_type Node : : children ( ) const throw ( ) {
return _contents . size ( ) ;
}
const Node & Node : : operator [ ] ( Node : : size_type child ) const
throw ( access_error ) try {
return * _contents . at ( child ) ;
} catch ( . . . ) {
throw out_of_range ( * this , child ) ;
}
Node & Node : : operator [ ] ( Node : : size_type child ) throw ( access_error ) try {
return * _contents . at ( child ) ;
} catch ( . . . ) {
throw out_of_range ( * this , child ) ;
}
const Node & Node : : operator [ ] ( const std : : string & child ) const
throw ( access_error ) {
const Node * const t ( find ( child ) ) ;
if ( ! t ) throw access_error ( * this , child ) ;
return * t ;
}
Node & Node : : operator [ ] ( const std : : string & child ) throw ( access_error ) {
Node * const t ( find ( child ) ) ;
if ( ! t ) throw access_error ( * this , child ) ;
return * t ;
}
std : : string Node : : operator * ( ) const throw ( ) {
return text ( ) ;
}
Node & Node : : operator = ( const std : : string & contents ) throw ( tag_expected ,
type_mismatch ) {
return text ( contents ) ;
}
std : : ostream & operator < < ( std : : ostream & o , const Node & t ) throw ( ) {
return t . out ( o ) ;
}
Node * Node : : find ( const std : : string & child ) const throw ( ) {
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it ) {
if ( ( * it ) - > name ( ) = = child ) return * it ;
}
return 0 ;
}
std : : auto_ptr < Node > Node : : clone ( Node * p ) const throw ( ) {
std : : auto_ptr < Node > c ( clone ( ) ) ;
c - > _parent = p ;
return c ;
}
//----------------------------------------------------------------------------
String : : String ( std : : string name , const std : : string & text ) throw ( ) :
Node ( name ) , _text ( text ) {
}
std : : auto_ptr < Node > String : : clone ( ) const throw ( ) {
return std : : auto_ptr < Node > ( new String ( * this ) ) ;
}
std : : string String : : text ( ) const throw ( ) {
return _text ;
}
String & String : : text ( const std : : string & txt ) throw ( tag_expected ,
type_mismatch ) {
_text = txt ;
return * this ;
}
std : : ostream & String : : out ( std : : ostream & o , unsigned int level ) const throw ( ) {
if ( _text . size ( ) ) {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < ' > ' < < _text < < " </ " < < name ( ) < < ' > ' ;
} else {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < " /> " ;
}
return o ;
}
String & String : : append ( const Node & o ) throw ( cannot_have_children ) {
throw cannot_have_children ( * this , o ) ;
}
Node & String : : operator = ( const std : : string & contents ) throw ( ) {
return text ( contents ) ;
}
//----------------------------------------------------------------------------
UnsingedInteger : : UnsingedInteger ( std : : string name , const std : : string & text ) throw ( ) :
Node ( name ) , _text ( text ) {
}
std : : auto_ptr < Node > UnsingedInteger : : clone ( ) const throw ( ) {
return std : : auto_ptr < Node > ( new UnsingedInteger ( * this ) ) ;
}
std : : string UnsingedInteger : : text ( ) const throw ( ) {
return _text ;
}
UnsingedInteger & UnsingedInteger : : text ( const std : : string & txt ) throw ( tag_expected ,
type_mismatch ) {
_text = txt ;
return * this ;
}
std : : ostream & UnsingedInteger : : out ( std : : ostream & o , unsigned int level ) const throw ( ) {
if ( _text . size ( ) ) {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < ' > ' < < _text < < " </ " < < name ( ) < < ' > ' ;
} else {
o < < std : : string ( level , ' \t ' ) < < ' < ' < < name ( ) ;
for ( Attributes : : const_iterator it ( _attributes . begin ( ) ) ;
it ! = _attributes . end ( ) ; + + it )
o < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
o < < " /> " ;
}
return o ;
}
UnsingedInteger & UnsingedInteger : : append ( const Node & o ) throw ( cannot_have_children ) {
throw cannot_have_children ( * this , o ) ;
}
Node & UnsingedInteger : : operator = ( const std : : string & contents ) throw ( ) {
return text ( contents ) ;
}
//----------------------------------------------------------------------------
Factory : : Factory ( const Node & t ) throw ( ) : _template ( t . clone ( ) ) { }
const Node & Factory : : operator * ( ) const throw ( ) {
return * _template ;
}
std : : auto_ptr < Node > Factory : : 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 ) {
std : : auto_ptr < Node > node ( _template - > clone ( ) ) ;
node - > clear ( ) ;
Tag res ;
try {
res = tag ( is , * node ) ;
} catch ( missing_end_tag & ) {
throw empty_stream ( * node , is , res ) ;
}
* node < < res . attributes ;
while ( true ) switch ( res . type ) {
case END : throw wrong_end_tag ( * node , is , res ) ;
case EMPTY : return node ; // empty
case START : return read ( is , * _template ) ;
case SPECIAL : break ; //! @todo ignored could be stored
}
}
bool Factory : : ws ( char c ) const throw ( ) {
return c = = ' ' | | c = = ' \t ' | | c = = ' \n ' | | c = = ' \r ' ;
}
std : : auto_ptr < Node > Factory : : read ( std : : istream & is , const Node & node )
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 ) {
std : : auto_ptr < Node > result ( node . clone ( ) ) ;
result - > clear ( ) ;
for ( bool finished ( false ) ; is & & ! finished ; ) {
Tag res ( tag ( is , node ) ) ;
if ( res . text . size ( ) ) result - > text ( res . text ) ;
switch ( res . type ) {
case END : {
if ( res . attributes . size ( ) ) throw attributes_in_end_tag ( node , is , res ) ;
if ( res . name ! = node . name ( ) ) throw wrong_end_tag ( node , is , res ) ;
finished = true ;
} break ;
case EMPTY : {
* result < < ( node [ res . name ] . clone ( ) - > clear ( ) < < res . attributes ) ;
} break ;
case START : {
* result < < ( * read ( is , node [ res . name ] ) < < res . attributes ) ;
} break ;
case SPECIAL : break ; //! @todo ignored could be stored
}
}
return result ;
}
Tag Factory : : 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 ) {
char c ( 0 ) ;
Tag tag ( ( Tag ) { " " , START , " " , Attributes ( ) } ) ;
while ( is & & is . get ( c ) & & ws ( c ) ) ; // skip ws
if ( ! is ) throw missing_end_tag ( position , is , tag ) ;
if ( c ! = ' < ' ) do tag . text + = c ; while ( is & & is . get ( c ) & & c ! = ' < ' ) ;
bool nameRead ( false ) ;
for ( char last ( c ) ; is & & is . get ( c ) & & c ! = ' > ' ; last = c ) switch ( c ) {
case ' ' : case ' \t ' : case ' \n ' : case ' \r ' :
if ( ! nameRead & & tag . name . size ( ) ) nameRead = true ;
break ;
case ' / ' :
if ( ! nameRead & & tag . name . size ( ) ) nameRead = true ;
if ( tag . type ! = START ) throw second_slash_in_tag ( position , is , tag , c ) ;
tag . type = nameRead ? EMPTY : END ;
break ;
case ' ! ' : case ' ? ' :
if ( last = = ' < ' ) { // <! tag or <?xml.. starts
do tag . special + = c ; while ( c ! = ' > ' & & is & & is . get ( c ) ) ;
return tag ;
}
default :
if ( tag . type = = EMPTY ) throw character_after_slash ( position , is , tag , c ) ;
if ( nameRead ) { // read attribute
std : : string attrname ( 1 , c ) , attrvalue ;
while ( is & & is . get ( c ) & & c ! = ' = ' & & ! ws ( c ) ) attrname + = c ;
while ( c ! = ' = ' & & is & & is . get ( c ) & & ws ( c ) ) ; // skip ws, search '='
if ( c = = ' = ' ) { // get the value
while ( is & & is . get ( c ) & & ws ( c ) ) ; // skip ws
if ( c ! = ' " ' )
throw attribute_value_not_quoted ( position , is , tag , c , attrname ) ;
while ( is & & is . get ( c ) & & c ! = ' " ' ) attrvalue + = c ;
if ( c ! = ' " ' )
throw attribute_value_not_quoted ( position , is , tag , c , attrname ) ;
} else is . unget ( ) ; // read too far
if ( tag . attributes . find ( attrname ) ! = tag . attributes . end ( ) )
throw duplicate_attribute ( position , is , tag , attrname ) ;
tag . attributes [ attrname ] = attrvalue ;
} else { // part of a tag name
tag . name + = c ;
}
}
return tag ;
}
}