#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 std::ostream;
+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;
}
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);
}
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
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());
}
}
}
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 ? "1" : "0";
}
-cxml::Document::~Document ()
+void
+cxml::Node::add_string_attribute (string name, string value)
{
- delete _parser;
+ _attributes.push_back (make_pair (name, value));
}
void
-cxml::Document::read_file (filesystem::path file)
+cxml::Node::add_bool_attribute (string name, bool value)
{
- if (!filesystem::exists (file)) {
+ add_string_attribute (name, value ? "1" : "0");
+}
+
+cxml::NodePtr
+cxml::Node::add_string_child (string name, string content)
+{
+ NodePtr n = add_child (name);
+ n->set_string_content (content);
+ return n;
+}
+
+cxml::NodePtr
+cxml::Node::add_bool_child (std::string name, bool content)
+{
+ NodePtr n = add_child (name);
+ n->set_bool_content (content);
+ return n;
+}
+
+void
+cxml::Document::read_file (boost::filesystem::path 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::take_root_node ()
+cxml::Document::read_string (string s)
{
- if (!_parser) {
- throw cxml::Error ("could not parse XML");
- }
+ xmlpp::DomParser parser;
+ stringstream t (s);
+ parser.parse_stream (t);
+ read (parser.get_document()->get_root_node ());
+}
- _node = _parser->get_document()->get_root_node ();
- if (_node->get_name() != _root_name) {
+void
+cxml::Document::check_root_name (string r)
+{
+ if (name() != r) {
throw cxml::Error ("unrecognised root node");
}
}
+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_stream_formatted (ostream& stream, string coding) const
+{
+ xmlpp::Document doc;
+ write_to_xmlpp_document (doc);
+ doc.write_to_stream_formatted (stream, coding);
+}
+
+string
+cxml::Document::write_to_string (std::string coding) const
+{
+ xmlpp::Document doc;
+ write_to_xmlpp_document (doc);
+ return 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);
+ }
+}