/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# include <xml-cxx/xml.hxx>
# include <iostream>
# include <sstream>
# include <cstdlib>
# include <cassert>
# 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 {
//================================================================= EXCEPTIONS
//----------------------------------------------------------------------------
exception : : exception ( std : : string reason ) throw ( ) :
_what ( reason ) , _node ( 0 ) {
}
exception : : exception ( std : : string reason , const Node & t ) throw ( ) :
_what ( reason ) , _node ( t . clone ( ) . release ( ) ) {
}
exception : : ~ exception ( ) throw ( ) {
delete _node ;
}
void exception : : line ( unsigned long line ) throw ( ) {
std : : stringstream ss ;
ss < < line ;
_what + = " \n at line: " + ss . str ( ) ;
}
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 , const Tag & tag , char c ) throw ( ) :
exception ( reason , t ) , _pos ( is . tellg ( ) ) , _tag ( new Tag ( tag ) ) , _char ( c ) {
}
stream_error : : stream_error ( const std : : string & reason , const Node & t ,
std : : istream & is ) throw ( ) :
exception ( reason , t ) , _pos ( is . tellg ( ) ) , _tag ( 0 ) , _char ( 0 ) {
}
stream_error : : ~ stream_error ( ) throw ( ) {
delete _tag ;
}
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 < < " ) " ;
if ( _tag ) {
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 ( ) ;
}
//============================================================================
//----------------------------------------------------------------------------
//! Copy an attribute.
Attributes : : Value : : Value ( const value_type & o ) throw ( ) :
Attributes : : value_type ( o ) {
}
//! Construct an empty attribute.
Attributes : : Value : : Value ( const std : : string & name ) throw ( ) :
Attributes : : value_type ( name , std : : string ( ) ) {
}
//! Construct an attribute with name an value.
Attributes : : Value : : Value ( const std : : string & name ,
const std : : string & value ) throw ( ) :
Attributes : : value_type ( name , value ) {
}
//! Assign a value.
Attributes : : Value & Attributes : : Value : : operator = ( const std : : string & value )
throw ( ) {
second = value ;
return * this ;
}
//! Get the attribute name.
const std : : string & Attributes : : Value : : name ( ) const throw ( ) {
return first ;
}
//! Get the attribute value.
const std : : string & Attributes : : Value : : value ( ) const throw ( ) {
return second ;
}
//! Get the attribute value.
std : : string & Attributes : : Value : : value ( ) throw ( ) {
return second ;
}
//! Convert the attribute to a boolean.
Attributes : : Value : : operator bool ( ) const throw ( ) {
/*! @return @c true if the value is set and not equal to one of:
@ c false @ c no @ c 0. */
return ! ( second . size ( ) | | second = = " false " | | second = = " no " | | second = = " 0 " ) ;
}
//! Convert the attribute to a number.
Attributes : : Value : : operator unsigned long ( ) const throw ( ) {
std : : stringstream ss ( second ) ;
int i ( 0 ) ;
ss > > i ;
return i ;
}
//! Convert the attribute to a space separated list.
Attributes : : Value : : operator List ( ) const throw ( ) {
return toList ( ) ;
}
//! Convert the attribute to a space separated list.
Attributes : : List Attributes : : Value : : toList ( const std : : string & separators )
const throw ( ) {
List l ;
for ( std : : string : : size_type it ( 0 ) , pos ( 0 ) ;
it ! = std : : string : : npos & &
( ( pos = second . find_first_of ( separators , it ) ) , true ) ;
it = pos ! = std : : string : : npos ? + + pos : std : : string : : npos )
if ( pos = = std : : string : : npos )
l . push_back ( second . substr ( it ) ) ;
else
l . push_back ( second . substr ( it , pos - it ) ) ;
return l ;
}
std : : string Attributes : : Value : : front ( const std : : string & separators ) const
throw ( empty_attribute_list ) {
List l ( toList ( separators ) ) ;
if ( ! l . size ( ) ) throw empty_attribute_list ( first ) ;
return l . front ( ) ;
}
//----------------------------------------------------------------------------
//! Empty attribute list
Attributes : : Attributes ( ) throw ( ) { }
//! Attribute list with first one empty attribute given.
Attributes : : Attributes ( const std : : string & empty ) throw ( ) {
insert ( Value ( empty ) ) ;
}
//! Attribute list with first attribute given.
Attributes : : Attributes ( const std : : string & key ,
const std : : string & value ) throw ( ) {
insert ( Value ( key , value ) ) ;
}
//! Add a new key-value pair to the attribute list.
Attributes & Attributes : : operator < < ( const Attributes : : Value & v ) throw ( ) {
insert ( v ) ;
return * this ;
}
//! Add a new empty key to the attribute list.
Attributes & Attributes : : operator < < ( const std : : string & key ) throw ( ) {
insert ( Value ( key ) ) ;
return * this ;
}
//----------------------------------------------------------------------------
//! Nodes must be given a name.
/*! Unnamed nodes are not allowed, therefore there's no default
constructor . */
Node : : Node ( std : : string name ,
Node : : size_type min , Node : : size_type max ) throw ( ) :
_name ( name ) , _parent ( 0 ) , _min ( min ) , _max ( max ) {
}
Node : : Node ( const Node & o ) throw ( ) :
_attributes ( o . _attributes ) , _name ( o . name ( ) ) , _parent ( 0 ) ,
_min ( o . _min ) , _max ( o . _max ) {
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 ;
_min = o . _min ;
_max = o . _max ;
for ( Contents : : const_iterator it ( o . _contents . begin ( ) ) ;
it ! = o . _contents . end ( ) ; + + it )
_contents . push_back ( ( * it ) - > clone ( this ) . release ( ) ) ;
}
Node : : ~ Node ( ) throw ( ) {
clear ( ) ;
}
//! Clones But clears the parent.
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 ;
}
Node & Node : : min ( Node : : size_type m ) throw ( ) {
_min = m ;
return * this ;
}
Node : : size_type Node : : min ( ) const throw ( ) {
return _min ;
}
Node & Node : : max ( Node : : size_type m ) throw ( ) {
_max = m ;
return * this ;
}
Node : : size_type Node : : max ( ) const throw ( ) {
return _max ;
}
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 ? " xml::mandatory " : " xml::optional " ;
return * this ;
}
Node & Node : : attr ( const std : : string & name , const std : : string & deflt )
throw ( ) {
_attributes [ name ] = deflt ;
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 ] ;
}
const Attributes : : Value Node : : attribute ( const std : : string & name )
const throw ( attribute_not_available ) {
Attributes : : const_iterator it ( _attributes . find ( name ) ) ;
if ( it ! = _attributes . end ( ) ) return * it ;
throw attribute_not_available ( * this , name ) ;
}
const Attributes & Node : : attributes ( ) const throw ( ) {
return _attributes ;
}
Attributes & Node : : attributes ( ) throw ( ) {
return _attributes ;
}
Node & Node : : limits ( size_type min , size_type max ) throw ( ) {
_min = min ;
_max = max ;
return * this ;
}
Node : : List Node : : list ( const std : : string & name ) const throw ( ) {
List res ;
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
if ( ( * it ) - > _name = = name ) res . push_back ( * it ) ;
return res ;
}
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 ( out_of_range ) try {
return * _contents . at ( child ) ;
} catch ( . . . ) {
throw out_of_range ( * this , child ) ;
}
Node & Node : : operator [ ] ( Node : : size_type child ) throw ( out_of_range ) 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 ,
Node : : size_type min , Node : : size_type max ) throw ( ) :
Node ( name , min , max ) {
}
String : : String ( std : : string name , const std : : string & text ,
Node : : size_type min , Node : : size_type max ) throw ( ) :
Node ( name , min , max ) , _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 ) ;
}
//----------------------------------------------------------------------------
UnsignedInteger : : UnsignedInteger ( std : : string name , unsigned long i ,
size_type min , size_type max ) throw ( ) :
String ( name ,
dynamic_cast < std : : stringstream & > ( std : : stringstream ( ) < < i ) . str ( ) ,
min , max ) {
}
std : : auto_ptr < Node > UnsignedInteger : : clone ( ) const throw ( ) {
return std : : auto_ptr < Node > ( new UnsignedInteger ( * this ) ) ;
}
UnsignedInteger & UnsignedInteger : : text ( const std : : string & txt )
throw ( tag_expected , type_mismatch ) {
std : : string : : size_type
start ( txt . find_first_not_of ( " \t \n \r " ) ) ,
last ( txt . find_last_not_of ( " \t \n \r " ) ) ;
if ( start = = std : : string : : npos ) { // empty - set to 0
_text = " 0 " ;
return * this ;
}
std : : string : : size_type pos ( txt . find_first_not_of ( " 0123456789 " , start ) ) ;
if ( pos < last | | pos = = last & & last = = start )
throw type_mismatch ( * this , txt ,
" unsigned integer may only contain numbers " ) ;
unsigned long i ( 0 ) ;
std : : stringstream ( txt ) > > i ;
std : : stringstream ss ;
ss < < i ;
_text = ss . str ( ) ;
return * this ;
}
unsigned long UnsignedInteger : : number ( ) const throw ( ) {
return number ( * this ) ;
}
unsigned long UnsignedInteger : : number ( const Node & node ) throw ( ) {
unsigned long i ( 0 ) ;
std : : stringstream ss ( node . text ( ) ) ;
ss > > i ;
return i ;
}
//----------------------------------------------------------------------------
Factory : : Factory ( const Node & t ) throw ( ) :
_template ( xml : : Node ( " <xml::start> " ) < < t ) , _line ( 0 ) {
_template [ 0 ] . min ( 1 ) ;
_template [ 0 ] . max ( 1 ) ;
}
const Node & Factory : : operator * ( ) const throw ( ) {
return _template [ 0 ] ;
}
std : : ostream & operator < < ( std : : ostream & os , const Factory & factory ) throw ( ) {
return factory . print ( os , * factory ) ;
}
std : : ostream & Factory : : print ( std : : ostream & os , const Node & node ,
unsigned int level ) throw ( ) {
if ( node . children ( ) ) {
os < < std : : string ( level , ' \t ' ) < < ' < ' < < node . name ( ) ;
for ( Attributes : : const_iterator it ( node . attributes ( ) . begin ( ) ) ;
it ! = node . attributes ( ) . end ( ) ; + + it )
os < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
os < < ' > ' ;
if ( dynamic_cast < const UnsignedInteger * > ( & node ) )
os < < " (Unsigned Integer " ;
else if ( dynamic_cast < const String * > ( & node ) )
os < < " (String " ;
else
os < < " (Node " ;
if ( node . min ( ) = = 1 & & node . max ( ) = = 1 )
os < < " , required exactly once) " ;
else if ( node . min ( ) = = 1 & & node . max ( ) = = 0 )
os < < " , required at least once) " ;
else if ( node . min ( ) = = 0 & & node . max ( ) = = 0 )
os < < " , 0..n) " ;
else if ( node . min ( ) = = 0 & & node . max ( ) = = 1 )
os < < " , optional) " ;
else
os < < " , " < < node . min ( ) < < " .. " < < node . max ( ) < < " ) " ;
os < < std : : endl ;
for ( Node : : size_type i ( 0 ) ; i < node . children ( ) ; + + i )
print ( os , node [ i ] , level + 1 ) ;
os < < std : : string ( level , ' \t ' ) < < " </ " < < node . name ( ) < < ' > ' < < std : : endl ;
} else {
os < < std : : string ( level , ' \t ' ) < < ' < ' < < node . name ( ) ;
for ( Attributes : : const_iterator it ( node . attributes ( ) . begin ( ) ) ;
it ! = node . attributes ( ) . end ( ) ; + + it )
os < < ' ' < < it - > first < < " = \" " < < it - > second < < ' " ' ;
os < < " /> " ;
if ( dynamic_cast < const UnsignedInteger * > ( & node ) )
os < < " (Unsigned Integer " ;
else if ( dynamic_cast < const String * > ( & node ) )
os < < " (String " ;
else
os < < " (Node " ;
if ( node . min ( ) = = 1 & & node . max ( ) = = 1 )
os < < " , required exactly once) " ;
else if ( node . min ( ) = = 1 & & node . max ( ) = = 0 )
os < < " , required at least once) " ;
else if ( node . min ( ) = = 0 & & node . max ( ) = = 0 )
os < < " , 0..n) " ;
else if ( node . min ( ) = = 0 & & node . max ( ) = = 1 )
os < < " , optional) " ;
else
os < < " , " < < node . min ( ) < < " .. " < < node . max ( ) < < " ) " ;
os < < std : : endl ;
}
return os ;
}
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 , duplicate_attribute ,
attributes_in_end_tag ,
illegal_attribute , mandatory_attribute_missing ,
wrong_node_number ) try {
_line = 1 ;
_open = 0 ;
std : : auto_ptr < Node > node ( read ( is , _template ) ) ;
if ( node - > children ( ) = = 0 )
throw tag_expected ( _template [ 0 ] , _template [ 0 ] . name ( ) ) ;
return ( * node ) [ 0 ] . clone ( ) ;
} catch ( exception & e ) {
e . line ( _line ) ;
throw ;
}
bool Factory : : ws ( char c ) throw ( ) {
static char last ( 0 ) ;
if ( ( c = = ' \n ' | | c = = ' \r ' ) & & last ! = ' \n ' & & last ! = ' \r ' ) + + _line ;
last = c ;
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 ,
illegal_attribute , mandatory_attribute_missing ,
wrong_node_number ) {
std : : auto_ptr < Node > result ( node . clone ( ) ) ;
result - > clear ( ) ;
while ( true ) {
Tag res ( tag ( is , node ) ) ;
if ( ! res . found ) return result ;
if ( res . text . size ( ) ) result - > text ( res . text ) ;
switch ( res . type ) {
case END : {
- - _open ;
if ( res . attributes . size ( ) ) throw attributes_in_end_tag ( node , is , res ) ;
if ( res . name ! = node . name ( ) ) throw wrong_end_tag ( node , is , res ) ;
} return result ;
case EMPTY : {
std : : auto_ptr < Node > current ( node [ res . name ] . clone ( ) ) ;
current - > clear ( ) < < res . attributes ;
* result < < * checkChildren ( node [ res . name ] , current , is ) ;
} break ;
case START : {
+ + _open ;
* result < < ( * checkChildren ( node [ res . name ] , read ( is , node [ res . name ] ) , is )
< < res . attributes ) ;
} break ;
case SPECIAL : break ; //! @todo ignored could be stored
}
}
}
std : : auto_ptr < Node > Factory : : checkChildren ( const xml : : Node & tpl ,
std : : auto_ptr < Node > node ,
std : : istream & is ) const
throw ( wrong_node_number ) {
for ( Node : : size_type i ( 0 ) ; i < tpl . children ( ) ; + + i )
if ( tpl [ i ] . min ( ) > 0 & & node - > list ( tpl [ i ] . name ( ) ) . size ( ) < tpl [ i ] . min ( )
| | 0 < tpl [ i ] . max ( ) & & tpl [ i ] . max ( ) < node - > list ( tpl [ i ] . name ( ) ) . size ( ) )
throw wrong_node_number ( * node , is , tpl [ i ] . name ( ) ,
node - > list ( tpl [ i ] . name ( ) ) . size ( ) ,
tpl [ i ] . min ( ) , tpl [ i ] . max ( ) ) ;
return node ;
}
Tag Factory : : tag ( std : : istream & is , const Node & position )
throw ( second_slash_in_tag , character_after_slash , tag_expected ,
missing_end_tag , attribute_value_not_quoted ,
access_error , duplicate_attribute , attributes_in_end_tag ,
illegal_attribute , mandatory_attribute_missing ,
wrong_start_tag ) {
char c ( 0 ) ;
Tag tag ( ( Tag ) { " " , START , " " , Attributes ( ) , " " , false } ) ;
while ( is & & is . get ( c ) & & ws ( c ) ) ; // skip ws
if ( is . eof ( ) ) {
if ( _open > 0 )
throw missing_end_tag ( position , is , tag ) ;
else
return tag ;
}
tag . found = true ;
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 ' \n ' : case ' \r ' :
if ( last ! = ' \n ' & & last ! = ' \r ' ) + + _line ;
case ' ' : case ' \t ' :
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
tag . special + = last ;
do tag . special + = c ; while ( c ! = ' > ' & & is & & is . get ( c ) ) ;
tag . type = SPECIAL ;
return tag ;
}
default :
if ( tag . type = = EMPTY ) throw character_after_slash ( position , is , tag , c ) ;
if ( nameRead ) { // read attribute
if ( tag . type ! = START ) throw attributes_in_end_tag ( position , is , tag ) ;
std : : string attrname ( 1 , c ) , attrvalue ;
while ( is & & is . get ( c ) & & c ! = ' = ' & & c ! = ' > ' & & c ! = ' / '
& & ! ws ( c ) ) attrname + = c ;
while ( ws ( c ) & & is & & is . get ( 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 ) ;
if ( ! position ( tag . name ) ) {
if ( tag . name . size ( ) )
throw wrong_start_tag ( position , is , tag ) ;
else
throw tag_expected ( position , tag . text ) ;
}
if ( position [ tag . name ] . attributes ( ) . find ( attrname )
= = position [ tag . name ] . attributes ( ) . end ( ) )
throw illegal_attribute ( position , is , tag , attrname ) ;
tag . attributes [ attrname ] = attrvalue ;
} else { // part of a tag name
tag . name + = c ;
}
}
if ( tag . type = = START | | tag . type = = EMPTY ) {
if ( ! position ( tag . name ) ) {
if ( tag . name . size ( ) )
throw wrong_start_tag ( position , is , tag ) ;
else
throw tag_expected ( position , tag . text ) ;
}
const xml : : Node & node ( position [ tag . name ] ) ;
for ( Attributes : : const_iterator it ( node . attributes ( ) . begin ( ) ) ;
it ! = node . attributes ( ) . end ( ) ; + + it )
if ( tag . attributes . find ( it - > first ) = = tag . attributes . end ( ) ) {
if ( it - > second = = " xml::mandatory " )
throw mandatory_attribute_missing ( position , is , tag , it - > first ) ;
else if ( it - > second ! = " xml::optional " )
tag . attributes . insert ( * it ) ;
}
}
return tag ;
}
}