/* Copyright (C) 2012-2014 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef LIBCXML_CXML_H #define LIBCXML_CXML_H #include #include #include #include #include #include #include #include #include #include /* Hack for OS X compile failure; see https://bugs.launchpad.net/hugin/+bug/910160 */ #ifdef check #undef check #endif namespace xmlpp { class Node; class Document; } namespace cxml { /** @brief An error */ class Error : public std::exception { public: /** Construct an Error exception. * @param message Error message. */ Error (std::string const & message) : _message (message) {} /** Error destructor */ ~Error () throw () {} /** @return error message. Caller must not free the returned * value. */ char const * what () const throw () { return _message.c_str (); } private: /** error message */ std::string _message; }; class Node; typedef boost::shared_ptr NodePtr; typedef std::list NodeList; typedef boost::shared_ptr ConstNodePtr; typedef std::list > KeyValueList; class Node : public boost::enable_shared_from_this { public: Node (); 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. * * If, for example, this object has been created with * a node named "Fred", we might have the following XML: * * * 42 * * * string_child ("Jim") would return "42" * number_child ("Jim") would return 42. * ...and so on. * * The methods not marked "optional" will throw an exception * if the child node is not present. The "optional" methods * will return an empty boost::optional<> in that case. * * All methods will also throw an exception if there is more * than one of the specified child node. */ std::string string_child (std::string c) const; boost::optional optional_string_child (std::string) const; bool bool_child (std::string) const; boost::optional optional_bool_child (std::string) const; template T number_child (std::string c) const { std::string s = string_child (c); boost::erase_all (s, " "); std::stringstream t; t.imbue (std::locale::classic ()); t << s; T n; t >> n; return n; } template boost::optional optional_number_child (std::string c) const { boost::optional s = optional_string_child (c); if (!s) { return boost::optional (); } std::string t = s.get (); boost::erase_all (t, " "); std::stringstream u; u.imbue (std::locale::classic ()); u << t; T n; u >> n; return n; } /* These methods look for an attribute of this node, in the * same way as the child methods do. */ std::string string_attribute (std::string) const; boost::optional optional_string_attribute (std::string) const; bool bool_attribute (std::string) const; boost::optional optional_bool_attribute (std::string) const; template T number_attribute (std::string c) const { std::string s = string_attribute (c); boost::erase_all (s, " "); std::stringstream t; t.imbue (std::locale::classic ()); t << s; T n; t >> n; return n; } template boost::optional optional_number_attribute (std::string c) const { boost::optional s = optional_string_attribute (c); if (!s) { return boost::optional (); } std::string t = s.get (); boost::erase_all (t, " "); std::stringstream u; u.imbue (std::locale::classic ()); u << t; T n; u >> n; return n; } /* Access to child nodes */ boost::shared_ptr child (std::string) const; boost::shared_ptr optional_child (std::string) const; NodeList children () const; NodeList children (std::string) const; /** Add a child node with a given name */ NodePtr add_child (std::string name, std::string namespace_prefix = "") { NodePtr n (new cxml::Node ()); n->set_namespace_prefix (namespace_prefix); n->set_name (name); _children.push_back (n); return n; } void set_namespace_declaration (std::string uri, std::string prefix = ""); KeyValueList namespace_declarations () const { return _namespace_declarations; } void set_content (std::string c) { _content = c; } /** @return The content of this node */ std::string content () const; void set_attribute (std::string name, std::string value); void set_namespace_prefix (std::string p) { _namespace_prefix = p; } /** @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 *, std::map* mapping = 0) const; protected: NodeList _children; private: std::string _name; std::string _content; std::string _namespace_prefix; KeyValueList _attributes; KeyValueList _namespace_declarations; mutable std::list _taken; }; cxml::NodePtr read_file (boost::filesystem::path); cxml::NodePtr read_stream (std::istream &); cxml::NodePtr read_string (std::string); void write_to_xmlpp_document (cxml::ConstNodePtr, xmlpp::Document &, std::map* mapping = 0); void write_to_file (cxml::ConstNodePtr, boost::filesystem::path); void write_to_file_formatted (cxml::ConstNodePtr, boost::filesystem::path); void write_to_stream_formatted (cxml::ConstNodePtr, std::ostream& stream); std::string write_to_string (cxml::ConstNodePtr); std::string write_to_string_formatted (cxml::ConstNodePtr); } #endif