diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-10-09 13:42:36 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-10-09 13:42:36 +0100 |
| commit | fd7dada1f4f5668e56a7cf3a268d22702f6ba52d (patch) | |
| tree | dabaa446843c772fb0a3ec92091fe11b595f29ab /src | |
| parent | 01edbdf34b0ad804106e184bd98b7d20c8f23cf1 (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.cc | 221 | ||||
| -rw-r--r-- | src/cxml.h | 136 |
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); + } +} @@ -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; }; } |
