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, map<cxml::ConstNodePtr, xmlpp::Node*>* mapping) const
76 xmlpp::Element* node = parent->add_child (_name, _namespace_prefix);
78 (*mapping)[shared_from_this()] = node;
81 if (!_content.empty ()) {
82 node->add_child_text (_content);
85 for (KeyValueList::const_iterator i = _namespace_declarations.begin(); i != _namespace_declarations.end(); ++i) {
86 node->set_namespace_declaration (i->first, i->second);
89 for (KeyValueList::const_iterator i = _attributes.begin(); i != _attributes.end(); ++i) {
90 node->set_attribute (i->first, i->second);
93 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
99 cxml::Node::child (string name) const
101 NodeList n = children (name);
103 throw cxml::Error ("duplicate XML tag " + name);
104 } else if (n.empty ()) {
105 throw cxml::Error ("missing XML tag " + name + " in " + _name);
112 cxml::Node::optional_child (string name) const
114 NodeList n = children (name);
116 throw cxml::Error ("duplicate XML tag " + name);
117 } else if (n.empty ()) {
125 cxml::Node::children () const
131 cxml::Node::children (string name) const
135 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
136 if ((*i)->name() == name) {
141 _taken.push_back (name);
146 cxml::Node::string_child (string c) const
148 return child(c)->content ();
152 cxml::Node::optional_string_child (string c) const
154 NodeList nodes = children (c);
155 if (nodes.size() > 1) {
156 throw cxml::Error ("duplicate XML tag " + c);
159 if (nodes.empty ()) {
160 return optional<string> ();
163 return nodes.front()->content();
167 cxml::Node::bool_child (string c) const
169 string const s = string_child (c);
170 return (s == "1" || s == "yes");
174 cxml::Node::optional_bool_child (string c) const
176 optional<string> s = optional_string_child (c);
178 return optional<bool> ();
181 return (s.get() == "1" || s.get() == "yes");
185 cxml::Node::ignore_child (string name) const
187 _taken.push_back (name);
191 cxml::Node::string_attribute (string name) const
193 KeyValueList::const_iterator i = _attributes.begin ();
194 while (i != _attributes.end() && i->first != name) {
198 if (i == _attributes.end ()) {
199 throw cxml::Error ("missing attribute");
206 cxml::Node::optional_string_attribute (string name) const
208 KeyValueList::const_iterator i;
209 while (i != _attributes.end() && i->first != name) {
213 if (i == _attributes.end ()) {
214 return optional<string> ();
221 cxml::Node::bool_attribute (string name) const
223 string const s = string_attribute (name);
224 return (s == "1" || s == "yes");
228 cxml::Node::optional_bool_attribute (string name) const
230 optional<string> s = optional_string_attribute (name);
232 return optional<bool> ();
235 return (s.get() == "1" || s.get() == "yes");
239 cxml::Node::done () const
241 for (NodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
242 if (find (_taken.begin(), _taken.end(), (*i)->name()) == _taken.end ()) {
243 throw cxml::Error ("unexpected XML node " + (*i)->name());
249 cxml::Node::content () const
255 cxml::Node::namespace_prefix () const
257 return _namespace_prefix;
261 cxml::Node::set_attribute (string name, string value)
263 KeyValueList::iterator i = _attributes.begin ();
264 while (i != _attributes.end() && i->first != name) {
268 if (i != _attributes.end ()) {
269 _attributes.erase (i);
272 _attributes.push_back (make_pair (name, value));
276 cxml::Node::set_namespace_declaration (string uri, string ns)
278 KeyValueList::iterator i = _namespace_declarations.begin ();
279 while (i != _namespace_declarations.end() && i->second != ns) {
283 if (i != _namespace_declarations.end ()) {
284 _namespace_declarations.erase (i);
287 _namespace_declarations.push_back (make_pair (uri, ns));
291 cxml::read_file (boost::filesystem::path file)
293 if (!boost::filesystem::exists (file)) {
294 throw cxml::Error ("XML file does not exist");
297 xmlpp::DomParser parser;
298 parser.parse_file (file.string ());
299 cxml::NodePtr node (new cxml::Node);
300 node->read (parser.get_document()->get_root_node ());
305 cxml::read_stream (istream& stream)
307 xmlpp::DomParser parser;
308 parser.parse_stream (stream);
309 cxml::NodePtr node (new cxml::Node);
310 node->read (parser.get_document()->get_root_node ());
315 cxml::read_string (string s)
317 xmlpp::DomParser parser;
319 parser.parse_stream (t);
320 cxml::NodePtr node (new cxml::Node);
321 node->read (parser.get_document()->get_root_node ());
326 cxml::write_to_xmlpp_document (cxml::ConstNodePtr node, xmlpp::Document& doc, map<cxml::ConstNodePtr, xmlpp::Node*>* mapping)
328 xmlpp::Element* root = doc.create_root_node (node->name ());
330 (*mapping)[node] = root;
333 cxml::KeyValueList namespace_declarations = node->namespace_declarations ();
334 for (cxml::KeyValueList::const_iterator i = namespace_declarations.begin(); i != namespace_declarations.end(); ++i) {
335 root->set_namespace_declaration (i->first, i->second);
338 cxml::NodeList children = node->children ();
339 for (cxml::NodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
340 (*i)->write (root, mapping);
345 cxml::write_to_file (cxml::ConstNodePtr node, boost::filesystem::path path)
348 write_to_xmlpp_document (node, doc);
349 doc.write_to_file (path.string ());
353 cxml::write_to_file_formatted (cxml::ConstNodePtr node, boost::filesystem::path path)
356 write_to_xmlpp_document (node, doc);
357 doc.write_to_file_formatted (path.string ());
361 cxml::write_to_stream_formatted (cxml::ConstNodePtr node, ostream& stream)
364 write_to_xmlpp_document (node, doc);
365 doc.write_to_stream_formatted (stream);
369 cxml::write_to_string (cxml::ConstNodePtr node)
372 write_to_xmlpp_document (node, doc);
373 return doc.write_to_string ();
377 cxml::write_to_string_formatted (cxml::ConstNodePtr node)
380 write_to_xmlpp_document (node, doc);
381 return doc.write_to_string_formatted ();