|
|
@ -170,9 +170,9 @@ namespace xml { |
|
|
|
return second; |
|
|
|
return second; |
|
|
|
} |
|
|
|
} |
|
|
|
//! Convert the attribute to a boolean.
|
|
|
|
//! 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:
|
|
|
|
/*! @return @c true if the value is set and not equal to one of:
|
|
|
|
@c false @c no @c 0. */ |
|
|
|
@c false @c no @c 0. */ |
|
|
|
|
|
|
|
Attributes::Value::operator bool() const throw() { |
|
|
|
return !(second.size()||second=="false"||second=="no"||second=="0"); |
|
|
|
return !(second.size()||second=="false"||second=="no"||second=="0"); |
|
|
|
} |
|
|
|
} |
|
|
|
//! Convert the attribute to a number.
|
|
|
|
//! Convert the attribute to a number.
|
|
|
@ -186,7 +186,8 @@ namespace xml { |
|
|
|
Attributes::Value::operator List() const throw() { |
|
|
|
Attributes::Value::operator List() const throw() { |
|
|
|
return toList(); |
|
|
|
return toList(); |
|
|
|
} |
|
|
|
} |
|
|
|
//! Convert the attribute to a space separated list.
|
|
|
|
//! Convert the attribute to list.
|
|
|
|
|
|
|
|
/*! @param separators a string containing a list of valid separators */ |
|
|
|
Attributes::List Attributes::Value::toList(const std::string& separators) |
|
|
|
Attributes::List Attributes::Value::toList(const std::string& separators) |
|
|
|
const throw() { |
|
|
|
const throw() { |
|
|
|
List l; |
|
|
|
List l; |
|
|
@ -200,6 +201,8 @@ namespace xml { |
|
|
|
l.push_back(second.substr(it, pos-it)); |
|
|
|
l.push_back(second.substr(it, pos-it)); |
|
|
|
return l; |
|
|
|
return l; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get the first value of an attribute containing a list of values.
|
|
|
|
|
|
|
|
/*! @copydoc xml::Attributes::Value::toList */ |
|
|
|
std::string Attributes::Value::front(const std::string& separators) const |
|
|
|
std::string Attributes::Value::front(const std::string& separators) const |
|
|
|
throw(empty_attribute_list) { |
|
|
|
throw(empty_attribute_list) { |
|
|
|
List l(toList(separators)); |
|
|
|
List l(toList(separators)); |
|
|
@ -231,11 +234,15 @@ namespace xml { |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//! Nodes must be given a name.
|
|
|
|
//! Nodes must be given a name.
|
|
|
|
/*! Unnamed nodes are not allowed, therefore there's no default
|
|
|
|
/*! Unnamed nodes are not allowed, therefore there's no default
|
|
|
|
constructor. */ |
|
|
|
constructor. |
|
|
|
|
|
|
|
@copydoc xml::Node::limits */ |
|
|
|
Node::Node(std::string name, |
|
|
|
Node::Node(std::string name, |
|
|
|
Node::size_type min, Node::size_type max) throw(): |
|
|
|
Node::size_type min, Node::size_type max) throw(): |
|
|
|
_name(name), _parent(0), _min(min), _max(max) { |
|
|
|
_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. */ |
|
|
|
Node::Node(const Node& o) throw(): |
|
|
|
Node::Node(const Node& o) throw(): |
|
|
|
_attributes(o._attributes), _name(o.name()), _parent(0), |
|
|
|
_attributes(o._attributes), _name(o.name()), _parent(0), |
|
|
|
_min(o._min), _max(o._max) { |
|
|
|
_min(o._min), _max(o._max) { |
|
|
@ -243,10 +250,12 @@ namespace xml { |
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Assign new node, keep parent.
|
|
|
|
|
|
|
|
/*! The parent remains unchanged, the node does not belong to the
|
|
|
|
|
|
|
|
same parent as the source of the copy. */ |
|
|
|
Node& Node::operator=(const Node& o) throw() { |
|
|
|
Node& Node::operator=(const Node& o) throw() { |
|
|
|
_attributes=o._attributes; |
|
|
|
_attributes=o._attributes; |
|
|
|
_name = o.name(); |
|
|
|
_name = o.name(); |
|
|
|
_parent = 0; |
|
|
|
|
|
|
|
_min = o._min; |
|
|
|
_min = o._min; |
|
|
|
_max = o._max; |
|
|
|
_max = o._max; |
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
@ -257,11 +266,17 @@ namespace xml { |
|
|
|
clear(); |
|
|
|
clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
//! Clones But clears the parent.
|
|
|
|
//! Clones But clears the parent.
|
|
|
|
|
|
|
|
/*! You get a new instance of the node, but detached from the
|
|
|
|
|
|
|
|
parent. It is then ready to be inserted below a new parent. */ |
|
|
|
std::auto_ptr<Node> Node::clone() const throw() { |
|
|
|
std::auto_ptr<Node> Node::clone() const throw() { |
|
|
|
std::auto_ptr<Node> res(new Node(*this)); |
|
|
|
std::auto_ptr<Node> res(new Node(*this)); |
|
|
|
res->_parent = 0; |
|
|
|
res->_parent = 0; |
|
|
|
return res; |
|
|
|
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() { |
|
|
|
std::ostream& Node::out(std::ostream& o, unsigned int level) const throw() { |
|
|
|
if (_contents.size()) { |
|
|
|
if (_contents.size()) { |
|
|
|
o<<std::string(level, '\t')<<'<'<<name(); |
|
|
|
o<<std::string(level, '\t')<<'<'<<name(); |
|
|
@ -282,6 +297,8 @@ namespace xml { |
|
|
|
} |
|
|
|
} |
|
|
|
return 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 Node::text() const throw() { |
|
|
|
std::string s; |
|
|
|
std::string s; |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
@ -289,17 +306,27 @@ namespace xml { |
|
|
|
s+=***it; |
|
|
|
s+=***it; |
|
|
|
return s; |
|
|
|
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) { |
|
|
|
Node& Node::text(const std::string& txt) throw(tag_expected, type_mismatch) { |
|
|
|
throw tag_expected(*this, txt); |
|
|
|
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) { |
|
|
|
Node& Node::append(const Node& o) throw(cannot_have_children) { |
|
|
|
_contents.push_back(o.clone(this).release()); |
|
|
|
_contents.push_back(o.clone(this).release()); |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Set a list of attributes.
|
|
|
|
|
|
|
|
/*! Existing attributes with the same name are overwritten. */ |
|
|
|
Node& Node::set(const Attributes& o) throw() { |
|
|
|
Node& Node::set(const Attributes& o) throw() { |
|
|
|
|
|
|
|
_attributes.clear(); |
|
|
|
_attributes.insert(o.begin(), o.end()); |
|
|
|
_attributes.insert(o.begin(), o.end()); |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Clears content and attributes.
|
|
|
|
Node& Node::clear() throw () { |
|
|
|
Node& Node::clear() throw () { |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|
it!=_contents.end(); ++it) |
|
|
|
it!=_contents.end(); ++it) |
|
|
@ -308,67 +335,131 @@ namespace xml { |
|
|
|
_attributes.clear(); |
|
|
|
_attributes.clear(); |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get the node's tag name.
|
|
|
|
std::string Node::name() const throw() { |
|
|
|
std::string Node::name() const throw() { |
|
|
|
return _name; |
|
|
|
return _name; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Set minimum number of instances (in a xml::Factory).
|
|
|
|
|
|
|
|
/*! @copydoc limits */ |
|
|
|
Node& Node::min(Node::size_type m) throw() { |
|
|
|
Node& Node::min(Node::size_type m) throw() { |
|
|
|
_min = m; |
|
|
|
_min = m; |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get minimum number of instances (in a xml::Factory).
|
|
|
|
|
|
|
|
/*! @copydoc limits */ |
|
|
|
Node::size_type Node::min() const throw() { |
|
|
|
Node::size_type Node::min() const throw() { |
|
|
|
return _min; |
|
|
|
return _min; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Set maximum number of instances (in a xml::Factory).
|
|
|
|
|
|
|
|
/*! @copydoc limits */ |
|
|
|
Node& Node::max(Node::size_type m) throw() { |
|
|
|
Node& Node::max(Node::size_type m) throw() { |
|
|
|
_max = m; |
|
|
|
_max = m; |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get maximum number of instances (in a xml::Factory).
|
|
|
|
|
|
|
|
/*! @copydoc limits */ |
|
|
|
Node::size_type Node::max() const throw() { |
|
|
|
Node::size_type Node::max() const throw() { |
|
|
|
return _max; |
|
|
|
return _max; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! @c true if node has a parent.
|
|
|
|
bool Node::isChild() const throw() { |
|
|
|
bool Node::isChild() const throw() { |
|
|
|
return _parent; |
|
|
|
return _parent; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get the parent node.
|
|
|
|
Node& Node::parent() const throw(no_parent) { |
|
|
|
Node& Node::parent() const throw(no_parent) { |
|
|
|
if (!_parent) throw no_parent(*this); |
|
|
|
if (!_parent) throw no_parent(*this); |
|
|
|
return *_parent; |
|
|
|
return *_parent; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Check if a specific attribute is set or not.
|
|
|
|
bool Node::hasAttr(const std::string& name) const throw() { |
|
|
|
bool Node::hasAttr(const std::string& name) const throw() { |
|
|
|
return _attributes.find(name)!=_attributes.end(); |
|
|
|
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() { |
|
|
|
Node& Node::attr(const std::string& name, bool mandatory) throw() { |
|
|
|
_attributes[name] = mandatory?"xml::mandatory":"xml::optional"; |
|
|
|
_attributes[name] = mandatory?"xml::mandatory":"xml::optional"; |
|
|
|
return *this; |
|
|
|
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) |
|
|
|
Node& Node::attr(const std::string& name, const std::string& deflt) |
|
|
|
throw() { |
|
|
|
throw() { |
|
|
|
_attributes[name] = deflt; |
|
|
|
_attributes[name] = deflt; |
|
|
|
return *this; |
|
|
|
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() { |
|
|
|
std::string Node::attr(const std::string& name) const throw() { |
|
|
|
Attributes::const_iterator it(_attributes.find(name)); |
|
|
|
Attributes::const_iterator it(_attributes.find(name)); |
|
|
|
if (it!=_attributes.end()) return it->second; |
|
|
|
if (it!=_attributes.end()) return it->second; |
|
|
|
return std::string(); |
|
|
|
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() { |
|
|
|
std::string& Node::attr(const std::string& name) throw() { |
|
|
|
return _attributes[name]; |
|
|
|
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 Attributes::Value Node::attribute(const std::string& name) |
|
|
|
const throw(attribute_not_available) { |
|
|
|
const throw(attribute_not_available) { |
|
|
|
Attributes::const_iterator it(_attributes.find(name)); |
|
|
|
Attributes::const_iterator it(_attributes.find(name)); |
|
|
|
if (it!=_attributes.end()) return *it; |
|
|
|
if (it!=_attributes.end()) return *it; |
|
|
|
throw attribute_not_available(*this, name); |
|
|
|
throw attribute_not_available(*this, name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get the list of attributes.
|
|
|
|
const Attributes& Node::attributes() const throw() { |
|
|
|
const Attributes& Node::attributes() const throw() { |
|
|
|
return _attributes; |
|
|
|
return _attributes; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get the list of attributes.
|
|
|
|
Attributes& Node::attributes() throw() { |
|
|
|
Attributes& Node::attributes() throw() { |
|
|
|
return _attributes; |
|
|
|
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() { |
|
|
|
Node& Node::limits(size_type min, size_type max) throw() { |
|
|
|
_min = min; |
|
|
|
_min = min; |
|
|
|
_max = max; |
|
|
|
_max = max; |
|
|
|
return *this; |
|
|
|
return *this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//! Get all children of a given node name
|
|
|
|
Node::List Node::list(const std::string& name) const throw() { |
|
|
|
Node::List Node::list(const std::string& name) const throw() { |
|
|
|
List res; |
|
|
|
List res; |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|