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;
35 using boost::shared_ptr;
36 using boost::optional;
43 cxml::Node::Node (xmlpp::Node const * node)
49 cxml::Node::read (xmlpp::Node const * node)
51 _name = node->get_name ();
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, _namespace_prefix);
78 if (!_content.empty ()) {
79 node->add_child_text (_content);
82 for (KeyValueList::const_iterator i = _namespace_declarations.begin(); i != _namespace_declarations.end(); ++i) {
83 node->set_namespace_declaration (i->first, i->second);
86 for (KeyValueList::const_iterator i = _attributes.begin(); i != _attributes.end(); ++i) {
87 node->set_attribute (i->first, i->second);
90 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
96 cxml::Node::child (string name) const
98 NodeList n = children (name);
100 throw cxml::Error ("duplicate XML tag " + name);
101 } else if (n.empty ()) {
102 throw cxml::Error ("missing XML tag " + name + " in " + _name);
109 cxml::Node::optional_child (string name) const
111 NodeList n = children (name);
113 throw cxml::Error ("duplicate XML tag " + name);
114 } else if (n.empty ()) {
122 cxml::Node::children () const
128 cxml::Node::children (string name) const
132 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
133 if ((*i)->name() == name) {
138 _taken.push_back (name);
143 cxml::Node::string_child (string c) const
145 return child(c)->content ();
149 cxml::Node::optional_string_child (string c) const
151 NodeList nodes = children (c);
152 if (nodes.size() > 1) {
153 throw cxml::Error ("duplicate XML tag " + c);
156 if (nodes.empty ()) {
157 return optional<string> ();
160 return nodes.front()->content();
164 cxml::Node::bool_child (string c) const
166 string const s = string_child (c);
167 return (s == "1" || s == "yes");
171 cxml::Node::optional_bool_child (string c) const
173 optional<string> s = optional_string_child (c);
175 return optional<bool> ();
178 return (s.get() == "1" || s.get() == "yes");
182 cxml::Node::ignore_child (string name) const
184 _taken.push_back (name);
188 cxml::Node::string_attribute (string name) const
190 KeyValueList::const_iterator i = _attributes.begin ();
191 while (i != _attributes.end() && i->first != name) {
195 if (i == _attributes.end ()) {
196 throw cxml::Error ("missing attribute");
203 cxml::Node::optional_string_attribute (string name) const
205 KeyValueList::const_iterator i;
206 while (i != _attributes.end() && i->first != name) {
210 if (i == _attributes.end ()) {
211 return optional<string> ();
218 cxml::Node::bool_attribute (string name) const
220 string const s = string_attribute (name);
221 return (s == "1" || s == "yes");
225 cxml::Node::optional_bool_attribute (string name) const
227 optional<string> s = optional_string_attribute (name);
229 return optional<bool> ();
232 return (s.get() == "1" || s.get() == "yes");
236 cxml::Node::done () const
238 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
239 if (find (_taken.begin(), _taken.end(), (*i)->name()) == _taken.end ()) {
240 throw cxml::Error ("unexpected XML node " + (*i)->name());
246 cxml::Node::content () const
252 cxml::Node::namespace_prefix () const
254 return _namespace_prefix;
258 cxml::Node::set_attribute (string name, string value)
260 KeyValueList::iterator i = _attributes.begin ();
261 while (i != _attributes.end() && i->first != name) {
265 if (i != _attributes.end ()) {
266 _attributes.erase (i);
269 _attributes.push_back (make_pair (name, value));
273 cxml::Node::set_namespace_declaration (string uri, string ns)
275 KeyValueList::iterator i = _namespace_declarations.begin ();
276 while (i != _namespace_declarations.end() && i->second != ns) {
280 if (i != _namespace_declarations.end ()) {
281 _namespace_declarations.erase (i);
284 _namespace_declarations.push_back (make_pair (uri, ns));
288 cxml::read_file (boost::filesystem::path file)
290 if (!boost::filesystem::exists (file)) {
291 throw cxml::Error ("XML file does not exist");
294 xmlpp::DomParser parser;
295 parser.parse_file (file.string ());
296 cxml::NodePtr node (new cxml::Node);
297 node->read (parser.get_document()->get_root_node ());
302 cxml::read_stream (istream& stream)
304 xmlpp::DomParser parser;
305 parser.parse_stream (stream);
306 cxml::NodePtr node (new cxml::Node);
307 node->read (parser.get_document()->get_root_node ());
312 cxml::read_string (string s)
314 xmlpp::DomParser parser;
316 parser.parse_stream (t);
317 cxml::NodePtr node (new cxml::Node);
318 node->read (parser.get_document()->get_root_node ());
323 write_to_xmlpp_document (cxml::ConstNodePtr node, xmlpp::Document& doc)
325 xmlpp::Element* root = doc.create_root_node (node->name ());
327 cxml::KeyValueList namespace_declarations = node->namespace_declarations ();
328 for (cxml::KeyValueList::const_iterator i = namespace_declarations.begin(); i != namespace_declarations.end(); ++i) {
329 root->set_namespace_declaration (i->first, i->second);
332 cxml::NodeList children = node->children ();
333 for (cxml::NodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
339 cxml::write_to_file (cxml::ConstNodePtr node, boost::filesystem::path path)
342 write_to_xmlpp_document (node, doc);
343 doc.write_to_file (path.string ());
347 cxml::write_to_file_formatted (cxml::ConstNodePtr node, boost::filesystem::path path)
350 write_to_xmlpp_document (node, doc);
351 doc.write_to_file_formatted (path.string ());
355 cxml::write_to_stream_formatted (cxml::ConstNodePtr node, ostream& stream)
358 write_to_xmlpp_document (node, doc);
359 doc.write_to_stream_formatted (stream);
363 cxml::write_to_string (cxml::ConstNodePtr node)
366 write_to_xmlpp_document (node, doc);
367 return doc.write_to_string ();
371 cxml::write_to_string_formatted (cxml::ConstNodePtr node)
374 write_to_xmlpp_document (node, doc);
375 return doc.write_to_string_formatted ();