/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# include <xml-cxx/xml.hxx>
# include <iostream>
# include <sstream>
# include <cstdlib>
# include <algorithm>
unsigned int MethodTrace : : _level ( 0 ) ;
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.
/*! @return @c true if the value is set and not equal to one of:
@ c false @ c no @ c 0. */
Attributes : : Value : : operator bool ( ) const throw ( ) {
return bool ( ) ;
}
//! Convert the attribute to a boolean.
/*! @return @c true if the value is set and not equal to one of:
@ c false @ c no @ c 0. */
bool Attributes : : Value : : toBool ( ) const throw ( ) {
return ! ( ! second . size ( ) | | second = = " false " | | second = = " no " | | second = = " 0 " ) ;
}
//! Convert the attribute to a number.
Attributes : : Value : : operator unsigned long ( ) const throw ( ) {
return toNumber ( ) ;
}
//! Convert the attribute to a number.
unsigned long Attributes : : Value : : toNumber ( ) 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 list.
/*! @param separators a string containing a list of valid separators */
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 ;
}
//! Get the first value of an attribute containing a list of values.
/*! @copydoc xml::Attributes::Value::toList
@ return the first element of the list . */
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 .
@ copydoc xml : : Node : : limits */
Node : : Node ( std : : string name ,
Node : : size_type min , Node : : size_type max ) throw ( ) :
_name ( name ) , _parent ( 0 ) , _min ( min ) , _max ( max ) {
}
//! Copy node, reset parent.
/*! The parent is reset, the node does not belong to the same parent
as the source of the copy .
@ see xml : : Node : : clone ( ) for more information on the parenting . */
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 ( ) throw ( ) {
clear ( ) ;
}
//! Assign new node, keep parent.
/*! The parent remains unchanged, the node does not belong to the
same parent as the source of the copy .
@ see xml : : Node : : clone ( ) for more information on the parenting . */
Node & Node : : operator = ( const Node & o ) throw ( ) {
clear ( ) ;
_attributes = o . _attributes ;
_name = o . name ( ) ;
_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 ( ) ) ;
}
//! Clones But resets the parent reference.
/*! You get a new instance of the node, but detached from the
parent . It is then ready to be inserted below a new parent .
If you clone ( or copy ) a node , the parent is not copied . This is
because otherwise the new now would need to be appended to the
parent ' s child list . That ' s most probably not
intended . Therefore , in a normal copy construction the parent is
set to @ c 0 ( no parent ) . Then the new node can be appended to a
parent if needed . In a copy assignment , the parent remains
uncanged and the other data is copied .
The user of this library doesn ' t have to and is not able to care
about the parenting . */
std : : auto_ptr < Node > Node : : clone ( ) const throw ( ) {
std : : auto_ptr < Node > res ( new Node ( * this ) ) ;
res - > _parent = 0 ;
return res ;
}
//! Stream XML.
/*! Streams the node including all attributes and children. It is
formatted with new - lines and tabulator indentation for human
readability . */
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 ;
}
//! Get the textual contents of a node.
/*! By default this is the concatenation of all child nodes' texts. */
std : : string Node : : text ( ) const throw ( ) {
std : : string s ;
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
s + = * * * it ;
return s ;
}
//! Set a text (forbidden in xml::Node)
/*! This method is only useful for child nodes, where it is
reimplemented . In xml : : Node , the parent of all nodes , it throws
xml : : tag_expected , since a xml : : Node may only contain sub - nodes
( formatted as xml - tags ) and no plain text . */
Node & Node : : text ( const std : : string & txt ) throw ( tag_expected , type_mismatch ) {
throw tag_expected ( * this , txt ) ;
}
//! Appends a new node at the end of all children.
Node & Node : : append ( const Node & o ) throw ( cannot_have_children ) {
_contents . push_back ( o . clone ( this ) . release ( ) ) ;
return * this ;
}
//! Removes a given child node.
Node & Node : : remove ( Node & n ) throw ( access_error ) {
Contents : : iterator it ( std : : find ( _contents . begin ( ) , _contents . end ( ) , & n ) ) ;
if ( it = = _contents . end ( ) ) throw access_error ( * this , n . name ( ) ) ;
_contents . erase ( it ) ;
return * this ;
}
//! Removes the first child node of a given name.
Node & Node : : remove ( const std : : string & n ) throw ( access_error ) {
Node * t ( find ( n ) ) ;
if ( ! t ) throw access_error ( * this , n ) ;
return remove ( * t ) ;
}
//! Removes the child node of a given position.
Node & Node : : remove ( size_type n ) throw ( out_of_range ) {
if ( n > = children ( ) ) throw out_of_range ( * this , n ) ;
_contents . erase ( _contents . begin ( ) + n ) ;
return * this ;
}
//! Set a list of attributes.
/*! Existing attributes with the same name are overwritten. */
Node & Node : : set ( const Attributes & o ) throw ( ) {
_attributes . clear ( ) ;
_attributes . insert ( o . begin ( ) , o . end ( ) ) ;
return * this ;
}
//! Clears content and attributes.
Node & Node : : clear ( ) throw ( ) {
for ( Contents : : const_iterator it ( _contents . begin ( ) ) ;
it ! = _contents . end ( ) ; + + it )
delete * it ;
_contents . clear ( ) ;
_attributes . clear ( ) ;
return * this ;
}
//! Get the node's tag name.
std : : string Node : : name ( ) const throw ( ) {
return _name ;
}
//! Set a new node's tag name.
Node & Node : : name ( const std : : string & n ) throw ( ) {
_name = n ;
return * this ;
}
//! Set minimum number of instances (in a xml::Factory).
/*! @copydoc limits */
Node & Node : : min ( Node : : size_type m ) throw ( ) {
_min = m ;
return * this ;
}
//! Get minimum number of instances (in a xml::Factory).
/*! @copydoc limits */
Node : : size_type Node : : min ( ) const throw ( ) {
return _min ;
}
//! Set maximum number of instances (in a xml::Factory).
/*! @copydoc limits */
Node & Node : : max ( Node : : size_type m ) throw ( ) {
_max = m ;
return * this ;
}
//! Get maximum number of instances (in a xml::Factory).
/*! @copydoc limits */
Node : : size_type Node : : max ( ) const throw ( ) {
return _max ;
}
//! @c true if node has a parent.
bool Node : : isChild ( ) const throw ( ) {
return _parent ;
}
//! Get the parent node.
Node & Node : : parent ( ) const throw ( no_parent ) {
if ( ! _parent ) throw no_parent ( * this ) ;
return * _parent ;
}
//! Check if a specific attribute is set or not.
bool Node : : hasAttr ( const std : : string & name ) const throw ( ) {
return _attributes . find ( name ) ! = _attributes . end ( ) ;
}
//! Declare an attribute template and specify whether it is mandatory
/*! Used for setting up attributes in xml::Factory:
@ code
xml : : Factory f ( xml : : Node ( " root " ) . attr ( " aname " , xml : : mandatory ) ;
@ endcode
If a factory reads from a stream , it verifies that only optional
or mandatory attributes are given and that mandatory attributes
are specified . Otherwise reading throws an exception . */
Node & Node : : attr ( const std : : string & name , bool mandatory ) throw ( ) {
_attributes [ name ] = mandatory ? " xml::mandatory " : " xml::optional " ;
return * this ;
}
//! Declare an attribute with given value.
/*! When used for setting up attributes in xml::Factory, it
specifies an optional attribute with given default value :
@ code
xml : : Factory f ( xml : : Node ( " root " ) . attr ( " aname " , " avalue " ) ;
@ endcode
If a factory reads from a stream and the specified attribute is
not given , it is set to @ c deflt . */
Node & Node : : attr ( const std : : string & name , const std : : string & deflt ) throw ( ) {
_attributes [ name ] = deflt ;
return * this ;
}
//! Get an attribute.
/*! Returns the attribute's value (empty if the attribute is not set) */
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 ( ) ;
}
//! Get an attribute.
/*! Returns the attribute's value (empty if the attribute is not set) */
std : : string & Node : : attr ( const std : : string & name ) throw ( ) {
return _attributes [ name ] ;
}
//! Get an attribute.
/*! Returns an attribute class or throws an exception if the
attribute is not set . This method is useful when you need
conversions or other methods as specified in
xml : : Attributes : : Value . */
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 ) ;
}
//! Get the list of attributes.
const Attributes & Node : : attributes ( ) const throw ( ) {
return _attributes ;
}
//! Get the list of attributes.
Attributes & Node : : attributes ( ) throw ( ) {
return _attributes ;
}
//! Pass a minimal and maximal number for this node in a xml file.
/*! Minimal and maximal values are verified when you use the node as
a template in a xml : : Factory . When the factory reads a stucture
from a stream through xml : : Factory : : read , then all the limits
are verified .
There are several ways to declare the limits .
- in the constructor xml : : Node : : Node
- minimum and maximum using method xml : : Node : : limits
- using methods xml : : Node : : min and xml : : Node : : max separately
It is recommended not to use the constructor , but the methods
xml : : Node : : limits , xml : : Node : : min and xml : : Node : : max , simply for
code readability .
The number @ c 0 means unlimited : xml : : Node : : min ( 0 ) means the
value is optional and xml : : Node : : max ( 0 ) means that there is no
upper limit . The only exception for this rule is the root
element of a structure passed to a xml : : Factory which must exist
exactly once .
Default is no limits : < code > 0. . n < / code > ,
which means that the node is optional and may be instatiated
multiple ( infinite , unlimited ) times . */
Node & Node : : limits ( size_type min , size_type max ) throw ( ) {
_min = min ;
_max = max ;
return * this ;
}
//! Get all immediate children of a given node name.
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 ;
}
//! Check if at least one child node of a given name exists.
bool Node : : operator ( ) ( const std : : string & child ) const throw ( ) {
return find ( child ) ;
}
//! Append a child at the end.
/*! @copydoc xml::Node::append */
Node & Node : : operator < < ( const Node & o ) throw ( cannot_have_children ) {
return append ( o ) ;
}
//! Add an empty attribute.
/*! @copydoc xml::Node::set */
Node & Node : : operator < < ( const Attributes & o ) throw ( ) {
return set ( o ) ;
}
//! Get the number of children.
Node : : size_type Node : : children ( ) const throw ( ) {
return _contents . size ( ) ;
}
//! Get a child by child-number (the n-th child).
/*! @param child number of the child to return: <code>child>=0</code> and
< code > child & lt ; xml : : Node : : children ( ) < / code > */
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 ) ;
}
/*! @copydoc xml::Node::operator[](Node::size_type child) const */
Node & Node : : operator [ ] ( Node : : size_type child ) throw ( out_of_range ) try {
return * _contents . at ( child ) ;
} catch ( . . . ) {
throw out_of_range ( * this , child ) ;
}
//! Get the first child of a given node name.
/*! @return the first child with matching node name */
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 ;
}
/*! @copydoc xml::Node::operator[](const std::string& child) const */
Node & Node : : operator [ ] ( const std : : string & child ) throw ( access_error ) {
Node * const t ( find ( child ) ) ;
if ( ! t ) throw access_error ( * this , child ) ;
return * t ;
}
//! Get the textual contents of a node.
/*! @copydoc xml::Node::text() */
std : : string Node : : operator * ( ) const throw ( ) {
return text ( ) ;
}
//! Set a text (forbidden in xml::Node)
/*! @copydoc xml::Node::text(const std::string& txt) */
Node & Node : : operator = ( const std : : string & contents ) throw ( tag_expected ,
type_mismatch ) {
return text ( contents ) ;
}
//! Write node in XML format to a stream.
/*! @copydoc xml::Node::out */
std : : ostream & operator < < ( std : : ostream & o , const Node & t ) throw ( ) {
return t . out ( o ) ;
}
//! Get a pointer to the first child of a given node name.
/*! This method does not throw an exception if the element does not
exist , but returns @ c 0. */
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 ;
}
//! Clone a node, but assign a new parent.
std : : auto_ptr < Node > Node : : clone ( Node * p ) const throw ( ) {
std : : auto_ptr < Node > c ( clone ( ) ) ;
c - > _parent = p ;
return c ;
}
//----------------------------------------------------------------------------
/*! @copydoc Node::Node(std::string name,
Node : : size_type min , Node : : size_type max ) */
String : : String ( std : : string name ,
Node : : size_type min , Node : : size_type max ) throw ( ) :
Node ( name , min , max ) {
}
//! Pass the text in the node.
/*! @copydoc Node::Node(std::string name,
Node : : size_type min , Node : : size_type 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 ;
}
//! An xml::String contains text: Set the text.
/*! Never throws an exception. */
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 ;
}
//! An xml::String has no child nodes: Always throws an exception.
String & String : : append ( const Node & o ) throw ( cannot_have_children ) {
throw cannot_have_children ( * this , o ) ;
}
//! An xml::String contains text: Set the text.
Node & String : : operator = ( const std : : string & contents ) throw ( ) {
return text ( contents ) ;
}
String : : operator std : : string ( ) const throw ( ) {
return text ( ) ;
}
String : : operator bool ( ) const throw ( ) {
bool res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator char ( ) const throw ( ) {
char res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator signed char ( ) const throw ( ) {
signed char res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator unsigned char ( ) const throw ( ) {
unsigned char res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator signed short ( ) const throw ( ) {
signed short res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator unsigned short ( ) const throw ( ) {
unsigned short res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator signed int ( ) const throw ( ) {
signed int res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator unsigned int ( ) const throw ( ) {
unsigned int res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator signed long ( ) const throw ( ) {
signed long res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator unsigned long ( ) const throw ( ) {
unsigned long res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator float ( ) const throw ( ) {
float res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
String : : operator double ( ) const throw ( ) {
double res ;
std : : stringstream ss ( text ( ) ) ;
ss > > res ;
return res ;
}
//----------------------------------------------------------------------------
/*! @copydoc Node::Node(std::string name,
Node : : size_type min , Node : : size_type max ) */
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 ) ) ;
}
//! An xml::UnsignedInteger must only contain an number.
/*! En exception is thrown, if the contents does not match a number. */
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 ;
}
//! Returns the contents as number.
unsigned long UnsignedInteger : : number ( ) const throw ( ) {
return number ( * this ) ;
}
//! Returns the contents as number.
unsigned long UnsignedInteger : : number ( const Node & node ) throw ( ) {
unsigned long i ( 0 ) ;
std : : stringstream ss ( node . text ( ) ) ;
ss > > i ;
return i ;
}
//----------------------------------------------------------------------------
//! To instanciate a factory, a template must be given.
Factory : : Factory ( const Node & t ) throw ( ) :
_template ( xml : : Node ( " <xml::start> " ) < < t ) , _line ( 0 ) {
_template [ 0 ] . min ( 1 ) ;
_template [ 0 ] . max ( 1 ) ;
}
//! Instanciates an invalid factory. A template must be assigned later.
Factory : : Factory ( ) throw ( ) :
_template ( xml : : Node ( " <xml::start> " ) ) , _line ( 0 ) {
}
//! Assign a template.
/*! If you don't pass a template at instanciation, you must call
this method later , or you will get xml : : factory_not_valid
exceptions when you try to use the factory . */
Factory & Factory : : operator = ( const Node & t ) throw ( ) {
_template = xml : : Node ( " <xml::start> " ) < < t ;
_template [ 0 ] . min ( 1 ) ;
_template [ 0 ] . max ( 1 ) ;
}
//! Get the template.
const Node & Factory : : operator * ( ) const throw ( factory_not_valid ) try {
return _template [ 0 ] ;
} catch ( . . . ) {
throw factory_not_valid ( ) ;
}
//! Access the (root node of the) template.
const Node * const Factory : : operator - > ( ) const throw ( factory_not_valid ) try {
return & _template [ 0 ] ;
} catch ( . . . ) {
throw factory_not_valid ( ) ;
}
//! Check whether the factory has been given a valid template.
Factory : : operator bool ( ) const throw ( ) {
return _template . children ( ) > 0 ;
}
//! Print the factory template's schema in human readable format.
/*! Calls xml::Factory::print */
std : : ostream & operator < < ( std : : ostream & os , const Factory & factory )
throw ( factory_not_valid ) {
return factory . print ( os , * factory ) ;
}
//! Print a node's schema description in human readable format.
/*! @todo May be changed to a XML Schema output later. */
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 ;
}
//! Restore a xml::Node tree from a stream, according to the given schema.
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 , factory_not_valid ) {
if ( _template . children ( ) = = 0 ) throw factory_not_valid ( ) ;
try {
_line = 1 ;
_open = 0 ;
std : : auto_ptr < Node > node ( read ( is , _template ) ) ;
if ( node - > children ( ) = = 0 )
throw tag_expected ( _template [ 0 ] ,
" nothing found, possibly empty stream " ) ;
return ( * node ) [ 0 ] . clone ( ) ;
} catch ( exception & e ) {
e . line ( _line ) ;
throw ;
}
}
void Factory : : reset ( ) throw ( ) {
_line = 0 ;
_open = 0 ;
_template = xml : : Node ( " <xml::start> " ) ;
}
Node & Factory : : operator * ( ) throw ( factory_not_valid ) try {
return _template [ 0 ] ;
} catch ( . . . ) {
throw factory_not_valid ( ) ;
}
Node * const Factory : : operator - > ( ) throw ( factory_not_valid ) try {
return & _template [ 0 ] ;
} catch ( . . . ) {
throw factory_not_valid ( ) ;
}
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 ;
}
//============================================================== Serialization
//----------------------------------------------------------------------------
Serialize : : Serialize ( ) throw ( ) { }
Serialize : : Serialize ( const std : : string & className ) throw ( ) :
_xmlFactory ( xml : : Node ( xml : : String ( className ) . limits ( 1 , 1 ) ) ) {
}
Serialize : : Serialize ( const Serialize & other ) throw ( ) {
copy ( other ) ;
}
Serialize : : ~ Serialize ( ) {
reset ( ) ;
}
Serialize & Serialize : : operator = ( const Serialize & other ) throw ( ) {
copy ( other ) ;
return * this ;
}
Serialize & Serialize : : className ( const std : : string & name ) throw ( ) {
xml : : Node node ( xml : : Node ( xml : : String ( name ) . limits ( 1 , 1 ) ) ) ;
if ( _xmlFactory ) {
for ( xml : : Node : : size_type i ( 0 ) ; i < _xmlFactory - > children ( ) ; + + i )
node < < ( * _xmlFactory ) [ i ] ;
}
_xmlFactory = node ;
return * this ;
}
Serialize & Serialize : : persist ( Serialize & ser ,
const std : : string & name ) throw ( ) {
if ( ser . optional ( ) ) {
_xmlNames [ name ] = & ser ;
ser . className ( name ) ;
* _xmlFactory < < * ser . _xmlFactory ;
std : : stringstream ss ;
} else {
ser . checkInit ( ) ;
_xmlNames [ name ] = & ser ;
xml : : Node schema ( * _xmlFactory ) ;
xml : : Node node ( xml : : Node ( name ) . limits ( 1 , 1 ) ) ;
for ( xml : : Node : : size_type i ( 0 ) ; i < ser . _xmlFactory - > children ( ) ; + + i )
node < < ( * ser . _xmlFactory ) [ i ] ;
_xmlFactory = schema < < node ;
return * this ;
}
return * this ;
}
Serialize & Serialize : : persist ( bool & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( char & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( unsigned char & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( signed char & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( unsigned short & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( signed short & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( unsigned int & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( signed int & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( unsigned long & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( signed long & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( float & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( double & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
Serialize & Serialize : : persist ( std : : string & member ,
const std : : string & name ) throw ( ) {
return persistSimpleType ( member , name ) ;
}
std : : ostream & Serialize : : saveXml ( std : : ostream & os ,
const std : : string & name ) const throw ( ) {
checkInit ( ) ;
xml : : Node node ( * _xmlFactory ) ;
if ( name . size ( ) ) node . name ( name ) ;
for ( std : : map < std : : string , Any > : : const_iterator
it ( _xmlNames . begin ( ) ) ;
it ! = _xmlNames . end ( ) ; + + it )
toNode ( it - > second , node [ it - > first ] ) ;
os < < node ;
return os ;
}
std : : istream & Serialize : : loadXml ( std : : istream & is , const std : : string & name ) {
checkInit ( ) ;
xml : : Factory factory ( _xmlFactory ) ;
if ( name . size ( ) ) factory - > name ( name ) ;
std : : auto_ptr < xml : : Node > node ( factory . read ( is ) ) ;
for ( std : : map < std : : string , Any > : : const_iterator
it ( _xmlNames . begin ( ) ) ;
it ! = _xmlNames . end ( ) ; + + it )
if ( ( * node ) ( it - > first ) )
fromNode ( it - > second , ( * node ) [ it - > first ] ) ;
else
clear ( it - > second ) ;
return is ;
}
std : : string Serialize : : schema ( ) const throw ( ) {
checkInit ( ) ;
std : : stringstream ss ;
ss < < * _xmlFactory ;
return ss . str ( ) ;
}
void Serialize : : registerFromNode ( Serialize : : FromNodeFunc fromNodeFunc ) {
_fromNode . insert ( fromNodeFunc ) ;
}
void Serialize : : registerToNode ( Serialize : : ToNodeFunc toNodeFunc ) {
_toNode . insert ( toNodeFunc ) ;
}
void Serialize : : registerClear ( Serialize : : ClearFunc clearFunc ) {
_clear . insert ( clearFunc ) ;
}
void Serialize : : initXmlMembers ( ) { }
void Serialize : : clear ( ) throw ( ) {
for ( std : : map < std : : string , Any > : : const_iterator
it ( _xmlNames . begin ( ) ) ;
it ! = _xmlNames . end ( ) ; + + it )
clear ( it - > second ) ;
}
void Serialize : : reset ( ) throw ( ) {
_xmlFactory . reset ( ) ;
_xmlNames . clear ( ) ;
}
void Serialize : : copy ( const Serialize & o ) throw ( ) {
reset ( ) ;
initXmlMembers ( ) ;
}
void Serialize : : fromNode ( Any member , const xml : : Node & node ) {
for ( std : : set < FromNodeFunc > : : const_iterator it ( _fromNode . begin ( ) ) ;
it ! = _fromNode . end ( ) ; + + it )
if ( ( * * it ) ( member , node ) ) return ; // found match
throw type_not_registered ( member . type ( ) . name ( ) , node . name ( ) , node ) ;
}
void Serialize : : toNode ( const Any member , xml : : Node & node ) const {
for ( std : : set < ToNodeFunc > : : const_iterator it ( _toNode . begin ( ) ) ;
it ! = _toNode . end ( ) ; + + it )
if ( ( * * it ) ( member , node ) ) return ; // found match
throw type_not_registered ( member . type ( ) . name ( ) , node . name ( ) , node ) ;
}
void Serialize : : clear ( Any member ) throw ( ) {
for ( std : : set < ClearFunc > : : const_iterator it ( _clear . begin ( ) ) ;
it ! = _clear . end ( ) ; + + it )
if ( ( * * it ) ( member ) ) return ; // found match
throw type_not_registered ( member . type ( ) . name ( ) ) ;
}
bool Serialize : : optional ( ) const throw ( ) {
return false ;
}
std : : set < Serialize : : FromNodeFunc > Serialize : : _fromNode ;
std : : set < Serialize : : ToNodeFunc > Serialize : : _toNode ;
std : : set < Serialize : : ClearFunc > Serialize : : _clear ;
//=============================================================== Assign Types
template < typename TYPE > bool assignFromNode ( Any member ,
const xml : : Node & node ) {
if ( ! any_cast < TYPE > ( & member ) ) return false ;
* any_cast < TYPE > ( member ) =
( TYPE ) dynamic_cast < const xml : : String & > ( node ) ;
return true ;
}
template < typename TYPE > bool assignToNode ( const Any member ,
xml : : Node & node ) {
if ( ! any_cast < TYPE > ( & member ) ) return false ;
std : : stringstream ss ;
ss < < * any_cast < TYPE > ( member ) ;
node . text ( ss . str ( ) ) ;
return true ;
}
template < > bool assignFromNode < bool > ( Any member ,
const xml : : Node & node ) {
if ( member . type ( ) ! = typeid ( bool ) ) return false ;
std : : string s ( * dynamic_cast < const xml : : String & > ( node ) ) ;
std : : string : : size_type
start ( s . find_first_not_of ( " \t \n \r " ) ) ,
end ( s . find_last_not_of ( " \t \n \r " ) ) ;
if ( start = = std : : string : : npos ) {
* any_cast < bool > ( member ) = false ;
} else {
s = s . substr ( start , end - start + 1 ) ;
* any_cast < bool > ( member ) =
s ! = " 0 " & & s ! = " false " & & s ! = " no " & & s ! = " off " ;
}
return true ;
}
template < > bool assignToNode < bool > ( const Any member ,
xml : : Node & node ) {
if ( member . type ( ) ! = typeid ( bool ) ) return false ;
node . text ( * any_cast < bool > ( member ) ? " true " : " false " ) ;
return true ;
}
template < > bool assignFromNode < Serialize > ( Any member ,
const xml : : Node & node ) {
if ( ! any_cast < Serialize > ( & member ) ) return false ;
if ( any_cast < Serialize > ( member ) - > optional ( ) ) {
( * any_cast < Serialize > ( member ) ) . fromNode ( member , node ) ;
return true ;
}
//! @todo improve this (inefficient)
std : : stringstream ss ; // simple but inefficient: rewrite and reread
ss < < node ;
any_cast < Serialize > ( member ) - > loadXml ( ss , node . name ( ) ) ;
/*
Serialize * ser ( any_cast < Serialize > ( member ) ) ;
for ( xml : : Node : : size_type i ( 0 ) ; i < node . children ( ) ; + + i )
ser - > fromNode ( ser - > _xmlNames [ * node [ i ] ] , node [ i ] ) ; */
return true ;
}
template < > bool assignToNode < Serialize > ( const Any member ,
xml : : Node & node ) {
if ( ! any_cast < Serialize > ( & member ) ) return false ;
if ( any_cast < Serialize > ( member ) - > optional ( ) ) {
any_cast < Serialize > ( member ) - > toNode ( member , node ) ;
return true ;
}
std : : stringstream ss ;
any_cast < Serialize > ( member ) - > saveXml ( ss , node . name ( ) ) ;
xml : : Factory factory ( node ) ;
node = * factory . read ( ss ) ;
return true ;
}
//================================================================ Clear Types
template < typename TYPE > bool clearMember ( Any member ) {
if ( ! any_cast < TYPE > ( & member ) ) return false ;
* any_cast < TYPE > ( member ) = 0 ;
return true ;
}
template < > bool clearMember < bool > ( Any member ) {
if ( member . type ( ) ! = typeid ( bool ) ) return false ;
* any_cast < bool > ( member ) = false ;
return true ;
}
template < > bool clearMember < std : : string > ( Any member ) {
if ( member . type ( ) ! = typeid ( bool ) ) return false ;
any_cast < std : : string > ( member ) - > clear ( ) ;
return true ;
}
template < > bool clearMember < Serialize > ( Any member ) {
if ( ! any_cast < Serialize > ( & member ) ) return false ;
any_cast < Serialize > ( member ) - > clear ( ) ;
return true ;
}
// Init To and From Node ---------------------------------------------------
namespace {
template < int NUM = MAX_NUM > struct RegisterTemplateForStdTypes {
RegisterTemplateForStdTypes < NUM - 1 > next ; // recurse to next until 0
RegisterTemplateForStdTypes ( ) {
Serialize : : registerToNode
( & assignToNode < typename ToType < NUM > : : Type > ) ;
Serialize : : registerFromNode
( & assignFromNode < typename ToType < NUM > : : Type > ) ;
Serialize : : registerClear
( & clearMember < typename ToType < NUM > : : Type > ) ;
}
} ;
template < > struct RegisterTemplateForStdTypes < 0 > { } ; // stop recursion
static RegisterTemplateForStdTypes < > init ; // execute initialisation
}
// ===========================================================================
}