summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-10-09 13:42:36 +0100
committerCarl Hetherington <cth@carlh.net>2014-10-09 13:42:36 +0100
commitfd7dada1f4f5668e56a7cf3a268d22702f6ba52d (patch)
treedabaa446843c772fb0a3ec92091fe11b595f29ab /src
parent01edbdf34b0ad804106e184bd98b7d20c8f23cf1 (diff)
Don't use xmlpp as the data storage; put things in cxml::Node members
instead. Add short-cuts for creating XML using libcxml.
Diffstat (limited to 'src')
-rw-r--r--src/cxml.cc221
-rw-r--r--src/cxml.h136
2 files changed, 221 insertions, 136 deletions
diff --git a/src/cxml.cc b/src/cxml.cc
index 810abf8..9a6a4e1 100644
--- a/src/cxml.cc
+++ b/src/cxml.cc
@@ -24,70 +24,107 @@
#include <libxml++/libxml++.h>
#include "cxml.h"
-using namespace std;
-using namespace boost;
+using std::pair;
+using std::list;
+using std::istream;
+using std::string;
+using std::make_pair;
+using std::map;
+using std::stringstream;
+using boost::shared_ptr;
+using boost::optional;
cxml::Node::Node ()
- : _node (0)
{
}
-cxml::Node::Node (xmlpp::Node* node)
- : _node (node)
+cxml::Node::Node (xmlpp::Node const * node)
{
+ read (node);
+}
+void
+cxml::Node::read (xmlpp::Node const * node)
+{
+ _name = node->get_name ();
+ _namespace_uri = node->get_namespace_uri ();
+ _namespace_prefix = node->get_namespace_prefix ();
+
+ xmlpp::Node::NodeList content = node->get_children ();
+ for (xmlpp::Node::NodeList::const_iterator i = content.begin(); i != content.end(); ++i) {
+ xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i);
+ if (v) {
+ _content += v->get_content ();
+ } else {
+ _children.push_back (cxml::NodePtr (new cxml::Node (*i)));
+ }
+ }
+
+ xmlpp::Element const * element = dynamic_cast<xmlpp::Element const *> (node);
+ if (element) {
+ xmlpp::Element::AttributeList attributes = element->get_attributes ();
+ for (list<xmlpp::Attribute*>::const_iterator i = attributes.begin(); i != attributes.end(); ++i) {
+ _attributes.push_back (make_pair ((*i)->get_name(), (*i)->get_value ()));
+ }
+ }
}
-string
-cxml::Node::name () const
+void
+cxml::Node::write (xmlpp::Node* parent) const
{
- assert (_node);
- return _node->get_name ();
+ xmlpp::Element* node = parent->add_child (_name);
+
+ if (!_content.empty ()) {
+ node->add_child_text (_content);
+ }
+
+ for (list<pair<string, string> >::const_iterator i = _attributes.begin(); i != _attributes.end(); ++i) {
+ node->set_attribute (i->first, i->second);
+ }
+
+ for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
+ (*i)->write (node);
+ }
}
-shared_ptr<cxml::Node>
+cxml::NodePtr
cxml::Node::node_child (string name) const
{
- list<shared_ptr<cxml::Node> > n = node_children (name);
+ NodeList n = node_children (name);
if (n.size() > 1) {
throw cxml::Error ("duplicate XML tag " + name);
} else if (n.empty ()) {
- throw cxml::Error ("missing XML tag " + name + " in " + _node->get_name());
+ throw cxml::Error ("missing XML tag " + name + " in " + _name);
}
return n.front ();
}
-shared_ptr<cxml::Node>
+cxml::NodePtr
cxml::Node::optional_node_child (string name) const
{
- list<shared_ptr<cxml::Node> > n = node_children (name);
+ NodeList n = node_children (name);
if (n.size() > 1) {
throw cxml::Error ("duplicate XML tag " + name);
} else if (n.empty ()) {
- return shared_ptr<cxml::Node> ();
+ return NodePtr ();
}
return n.front ();
}
-list<shared_ptr<cxml::Node> >
+cxml::NodeList
cxml::Node::node_children (string name) const
{
- /* XXX: using find / get_path should work here, but I can't follow
- how get_path works.
- */
-
- xmlpp::Node::NodeList c = _node->get_children ();
+ NodeList n;
- list<shared_ptr<cxml::Node> > n;
- for (xmlpp::Node::NodeList::iterator i = c.begin (); i != c.end(); ++i) {
- if ((*i)->get_name() == name) {
- n.push_back (shared_ptr<Node> (new Node (*i)));
+ for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
+ if ((*i)->name() == name) {
+ n.push_back (*i);
}
}
-
+
_taken.push_back (name);
return n;
}
@@ -101,7 +138,7 @@ cxml::Node::string_child (string c) const
optional<string>
cxml::Node::optional_string_child (string c) const
{
- list<shared_ptr<Node> > nodes = node_children (c);
+ NodeList nodes = node_children (c);
if (nodes.size() > 1) {
throw cxml::Error ("duplicate XML tag " + c);
}
@@ -140,33 +177,31 @@ cxml::Node::ignore_child (string name) const
string
cxml::Node::string_attribute (string name) const
{
- xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
- if (!e) {
- throw cxml::Error ("missing attribute");
+ list<pair<string, string> >::const_iterator i;
+ while (i != _attributes.end() && i->first != name) {
+ ++i;
}
- xmlpp::Attribute* a = e->get_attribute (name);
- if (!a) {
+ if (i == _attributes.end ()) {
throw cxml::Error ("missing attribute");
}
- return a->get_value ();
+ return i->second;
}
optional<string>
cxml::Node::optional_string_attribute (string name) const
{
- xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
- if (!e) {
- return optional<string> ();
+ list<pair<string, string> >::const_iterator i;
+ while (i != _attributes.end() && i->first != name) {
+ ++i;
}
- xmlpp::Attribute* a = e->get_attribute (name);
- if (!a) {
+ if (i == _attributes.end ()) {
return optional<string> ();
}
- return string (a->get_value ());
+ return i->second;
}
bool
@@ -190,10 +225,9 @@ cxml::Node::optional_bool_attribute (string name) const
void
cxml::Node::done () const
{
- xmlpp::Node::NodeList c = _node->get_children ();
- for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) {
- if (dynamic_cast<xmlpp::Element *> (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) {
- throw cxml::Error ("unexpected XML node " + (*i)->get_name());
+ for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
+ if (find (_taken.begin(), _taken.end(), (*i)->name()) == _taken.end ()) {
+ throw cxml::Error ("unexpected XML node " + (*i)->name());
}
}
}
@@ -201,92 +235,107 @@ cxml::Node::done () const
string
cxml::Node::content () const
{
- string content;
-
- xmlpp::Node::NodeList c = _node->get_children ();
- for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) {
- xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i);
- if (v) {
- content += v->get_content ();
- }
- }
-
- return content;
+ return _content;
}
string
cxml::Node::namespace_uri () const
{
- return _node->get_namespace_uri ();
+ return _namespace_uri;
}
string
cxml::Node::namespace_prefix () const
{
- return _node->get_namespace_prefix ();
+ return _namespace_prefix;
}
-cxml::Document::Document (string root_name)
- : _root_name (root_name)
+void
+cxml::Node::set_string_content (string c)
{
- _parser = new xmlpp::DomParser;
+ _content = c;
}
-cxml::Document::Document (string root_name, boost::filesystem::path file)
- : _root_name (root_name)
+void
+cxml::Node::set_bool_content (bool c)
{
- _parser = new xmlpp::DomParser ();
- read_file (file);
+ _content = c ? "yes" : "no";
}
-cxml::Document::Document ()
+cxml::NodePtr
+cxml::Node::add_string (string name, string content)
{
- _parser = new xmlpp::DomParser ();
+ NodePtr n = add (name);
+ n->set_string_content (content);
+ return n;
}
-
-cxml::Document::~Document ()
+
+cxml::NodePtr
+cxml::Node::add_bool (std::string name, bool content)
{
- delete _parser;
+ NodePtr n = add (name);
+ n->set_bool_content (content);
+ return n;
}
void
-cxml::Document::read_file (filesystem::path file)
+cxml::Document::read_file (boost::filesystem::path file)
{
- if (!filesystem::exists (file)) {
+ if (!boost::filesystem::exists (file)) {
throw cxml::Error ("XML file does not exist");
}
-
- _parser->parse_file (file.string ());
- take_root_node ();
+
+ xmlpp::DomParser parser;
+ parser.parse_file (file.string ());
+ read (parser.get_document()->get_root_node ());
}
void
cxml::Document::read_stream (istream& stream)
{
- _parser->parse_stream (stream);
- take_root_node ();
+ xmlpp::DomParser parser;
+ parser.parse_stream (stream);
+ read (parser.get_document()->get_root_node ());
}
void
cxml::Document::read_string (string s)
{
+ xmlpp::DomParser parser;
stringstream t (s);
- _parser->parse_stream (t);
- take_root_node ();
+ parser.parse_stream (t);
+ read (parser.get_document()->get_root_node ());
}
void
-cxml::Document::take_root_node ()
+cxml::Document::check_root_name (string r)
{
- if (!_parser) {
- throw cxml::Error ("could not parse XML");
- }
-
- _node = _parser->get_document()->get_root_node ();
- if (!_root_name.empty() && _node->get_name() != _root_name) {
+ if (name() != r) {
throw cxml::Error ("unrecognised root node");
- } else if (_root_name.empty ()) {
- _root_name = _node->get_name ();
}
}
+void
+cxml::Document::write_to_file_formatted (boost::filesystem::path path) const
+{
+ xmlpp::Document doc;
+ write_to_xmlpp_document (doc);
+ doc.write_to_file_formatted (path.string ());
+}
+
+void
+cxml::Document::write_to_string (std::string coding) const
+{
+ xmlpp::Document doc;
+ write_to_xmlpp_document (doc);
+ doc.write_to_string (coding);
+}
+
+void
+cxml::Document::write_to_xmlpp_document (xmlpp::Document& doc) const
+{
+ xmlpp::Element* root = doc.create_root_node (name ());
+ for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
+ (*i)->write (root);
+ }
+}
diff --git a/src/cxml.h b/src/cxml.h
index 8be978f..0542c4e 100644
--- a/src/cxml.h
+++ b/src/cxml.h
@@ -33,11 +33,8 @@
#undef check
#endif
-#include <glibmm.h>
-
namespace xmlpp {
class Node;
- class DomParser;
}
namespace cxml {
@@ -67,21 +64,15 @@ private:
};
class Node;
-typedef std::list<boost::shared_ptr<Node> > NodeList;
+typedef boost::shared_ptr<cxml::Node> NodePtr;
+typedef std::list<NodePtr> NodeList;
+typedef boost::shared_ptr<const cxml::Node> ConstNodePtr;
-/** @brief A wrapper for a xmlpp::Node which simplifies parsing */
class Node
{
public:
Node ();
-
- /** Construct a Node from an xmlpp::Node. This class will
- * not destroy the xmlpp::Node.
- * @param node xmlpp::Node.
- */
- Node (xmlpp::Node* node);
-
- std::string name () const;
+ Node (xmlpp::Node const *);
/* A set of methods which look up a child of this node by
* its name, and return its contents as some type or other.
@@ -142,14 +133,7 @@ public:
return n;
}
- /** This will mark a child as to be ignored when calling done() */
- void ignore_child (std::string) const;
-
- /** Check whether all children of this Node have been looked up
- * or passed to ignore_child(). If not, an exception is thrown.
- */
- void done () const;
-
+
/* These methods look for an attribute of this node, in the
* same way as the child methods do.
*/
@@ -191,56 +175,108 @@ public:
return n;
}
- /** @return The content of this node */
- std::string content () const;
- /** @return namespace URI of this node */
- std::string namespace_uri () const;
+ /* Setting content */
- /** @return namespace prefix of this node */
- std::string namespace_prefix () const;
+ void set_string_content (std::string content);
+ void set_bool_content (bool content);
+
+ template <class T>
+ void set_number_content (T content)
+ {
+ std::stringstream u;
+ u.imbue (std::locale::classic ());
+ u << content;
+ u >> _content;
+ }
+
+
+ /* Short-cuts to add nodes with content */
+
+ NodePtr add_string (std::string name, std::string content);
+ NodePtr add_bool (std::string name, bool content);
+
+ template <class T>
+ NodePtr add_number (std::string name, T content)
+ {
+ NodePtr n = add (name);
+ n->set_number_content (content);
+ return n;
+ }
+
+
+ /* Access to child nodes */
boost::shared_ptr<Node> node_child (std::string) const;
boost::shared_ptr<Node> optional_node_child (std::string) const;
-
NodeList node_children (std::string) const;
- xmlpp::Node* node () const {
- return _node;
+ /** Add a child node with a given name */
+ NodePtr add (std::string name)
+ {
+ NodePtr n (new cxml::Node ());
+ n->set_name (name);
+ _children.push_back (n);
+ return n;
}
-protected:
- xmlpp::Node* _node;
+ /** @return The content of this node */
+ std::string content () const;
+ /** @return namespace URI of this node */
+ std::string namespace_uri () const;
+ /** @return namespace prefix of this node */
+ std::string namespace_prefix () const;
+ /** This will mark a child as to be ignored when calling done() */
+ void ignore_child (std::string) const;
+ /** Check whether all children of this Node have been looked up
+ * or passed to ignore_child(). If not, an exception is thrown.
+ */
+ void done () const;
+ /** Set the name of the node.
+ * @param n New name.
+ */
+ void set_name (std::string n) {
+ _name = n;
+ }
+ /** @return Node name */
+ std::string name () const {
+ return _name;
+ }
+
+ /* We use xmlpp for parsing and writing XML out; these
+ methods help with that.
+ */
+ void read (xmlpp::Node const *);
+ void write (xmlpp::Node *) const;
+
+protected:
+ NodeList _children;
private:
- mutable std::list<Glib::ustring> _taken;
+ std::string _name;
+ std::string _content;
+ std::string _namespace_uri;
+ std::string _namespace_prefix;
+ std::list<std::pair<std::string, std::string> > _attributes;
+ mutable std::list<std::string> _taken;
};
-typedef boost::shared_ptr<cxml::Node> NodePtr;
-typedef boost::shared_ptr<const cxml::Node> ConstNodePtr;
-
class Document : public Node
{
public:
- Document ();
- Document (std::string root_name);
- Document (std::string root_name, boost::filesystem::path);
-
- virtual ~Document ();
+ Document () {}
void read_file (boost::filesystem::path);
void read_stream (std::istream &);
void read_string (std::string);
-
- std::string root_name () const {
- return _root_name;
- }
-
+
+ void check_root_name (std::string root_name);
+
+ void write_to_file_formatted (boost::filesystem::path) const;
+ void write_to_string (std::string) const;
+
private:
- void take_root_node ();
-
- xmlpp::DomParser* _parser;
- std::string _root_name;
+ void write_to_xmlpp_document (xmlpp::Document &) const;
};
}