2 Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <boost/filesystem.hpp>
23 #include <boost/algorithm/string.hpp>
24 #include <libxml++/libxml++.h>
33 using std::stringstream;
34 using boost::shared_ptr;
35 using boost::optional;
42 cxml::Node::Node (xmlpp::Node const * node)
48 cxml::Node::read (xmlpp::Node const * node)
50 _name = node->get_name ();
51 _namespace_uri = node->get_namespace_uri ();
52 _namespace_prefix = node->get_namespace_prefix ();
54 xmlpp::Node::NodeList content = node->get_children ();
55 for (xmlpp::Node::NodeList::const_iterator i = content.begin(); i != content.end(); ++i) {
56 xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i);
58 _content += v->get_content ();
60 _children.push_back (cxml::NodePtr (new cxml::Node (*i)));
64 xmlpp::Element const * element = dynamic_cast<xmlpp::Element const *> (node);
66 xmlpp::Element::AttributeList attributes = element->get_attributes ();
67 for (list<xmlpp::Attribute*>::const_iterator i = attributes.begin(); i != attributes.end(); ++i) {
68 _attributes.push_back (make_pair ((*i)->get_name(), (*i)->get_value ()));
74 cxml::Node::write (xmlpp::Node* parent) const
76 xmlpp::Element* node = parent->add_child (_name);
78 if (!_content.empty ()) {
79 node->add_child_text (_content);
82 for (list<pair<string, string> >::const_iterator i = _attributes.begin(); i != _attributes.end(); ++i) {
83 node->set_attribute (i->first, i->second);
86 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
92 cxml::Node::node_child (string name) const
94 NodeList n = node_children (name);
96 throw cxml::Error ("duplicate XML tag " + name);
97 } else if (n.empty ()) {
98 throw cxml::Error ("missing XML tag " + name + " in " + _name);
105 cxml::Node::optional_node_child (string name) const
107 NodeList n = node_children (name);
109 throw cxml::Error ("duplicate XML tag " + name);
110 } else if (n.empty ()) {
118 cxml::Node::node_children (string name) const
122 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
123 if ((*i)->name() == name) {
128 _taken.push_back (name);
133 cxml::Node::string_child (string c) const
135 return node_child(c)->content ();
139 cxml::Node::optional_string_child (string c) const
141 NodeList nodes = node_children (c);
142 if (nodes.size() > 1) {
143 throw cxml::Error ("duplicate XML tag " + c);
146 if (nodes.empty ()) {
147 return optional<string> ();
150 return nodes.front()->content();
154 cxml::Node::bool_child (string c) const
156 string const s = string_child (c);
157 return (s == "1" || s == "yes");
161 cxml::Node::optional_bool_child (string c) const
163 optional<string> s = optional_string_child (c);
165 return optional<bool> ();
168 return (s.get() == "1" || s.get() == "yes");
172 cxml::Node::ignore_child (string name) const
174 _taken.push_back (name);
178 cxml::Node::string_attribute (string name) const
180 list<pair<string, string> >::const_iterator i;
181 while (i != _attributes.end() && i->first != name) {
185 if (i == _attributes.end ()) {
186 throw cxml::Error ("missing attribute");
193 cxml::Node::optional_string_attribute (string name) const
195 list<pair<string, string> >::const_iterator i;
196 while (i != _attributes.end() && i->first != name) {
200 if (i == _attributes.end ()) {
201 return optional<string> ();
208 cxml::Node::bool_attribute (string name) const
210 string const s = string_attribute (name);
211 return (s == "1" || s == "yes");
215 cxml::Node::optional_bool_attribute (string name) const
217 optional<string> s = optional_string_attribute (name);
219 return optional<bool> ();
222 return (s.get() == "1" || s.get() == "yes");
226 cxml::Node::done () const
228 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
229 if (find (_taken.begin(), _taken.end(), (*i)->name()) == _taken.end ()) {
230 throw cxml::Error ("unexpected XML node " + (*i)->name());
236 cxml::Node::content () const
242 cxml::Node::namespace_uri () const
244 return _namespace_uri;
248 cxml::Node::namespace_prefix () const
250 return _namespace_prefix;
254 cxml::Node::set_string_content (string c)
260 cxml::Node::set_bool_content (bool c)
262 _content = c ? "yes" : "no";
266 cxml::Node::add_string (string name, string content)
268 NodePtr n = add (name);
269 n->set_string_content (content);
274 cxml::Node::add_bool (std::string name, bool content)
276 NodePtr n = add (name);
277 n->set_bool_content (content);
282 cxml::Document::read_file (boost::filesystem::path file)
284 if (!boost::filesystem::exists (file)) {
285 throw cxml::Error ("XML file does not exist");
288 xmlpp::DomParser parser;
289 parser.parse_file (file.string ());
290 read (parser.get_document()->get_root_node ());
294 cxml::Document::read_stream (istream& stream)
296 xmlpp::DomParser parser;
297 parser.parse_stream (stream);
298 read (parser.get_document()->get_root_node ());
302 cxml::Document::read_string (string s)
304 xmlpp::DomParser parser;
306 parser.parse_stream (t);
307 read (parser.get_document()->get_root_node ());
311 cxml::Document::check_root_name (string r)
314 throw cxml::Error ("unrecognised root node");
319 cxml::Document::write_to_file_formatted (boost::filesystem::path path) const
322 write_to_xmlpp_document (doc);
323 doc.write_to_file_formatted (path.string ());
327 cxml::Document::write_to_string (std::string coding) const
330 write_to_xmlpp_document (doc);
331 doc.write_to_string (coding);
335 cxml::Document::write_to_xmlpp_document (xmlpp::Document& doc) const
337 xmlpp::Element* root = doc.create_root_node (name ());
338 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {