Missing #include.
[libcxml.git] / src / cxml.h
1 /*
2     Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
3
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.
8
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.
13
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.
17
18 */
19
20 #ifndef LIBCXML_CXML_H
21 #define LIBCXML_CXML_H
22
23 #include <string>
24 #include <sstream>
25 #include <list>
26 #include <map>
27 #include <stdint.h>
28 #include <boost/shared_ptr.hpp>
29 #include <boost/optional.hpp>
30 #include <boost/filesystem.hpp>
31 #include <boost/algorithm/string/erase.hpp>
32 #include <boost/enable_shared_from_this.hpp>
33
34 /* Hack for OS X compile failure; see https://bugs.launchpad.net/hugin/+bug/910160 */
35 #ifdef check
36 #undef check
37 #endif
38
39 namespace xmlpp {
40         class Node;
41         class Document;
42 }
43
44 namespace cxml {
45
46 /** @brief An error */
47 class Error : public std::exception
48 {
49 public:
50         /** Construct an Error exception.
51          *  @param message Error message.
52          */
53         Error (std::string const & message) : _message (message) {}
54
55         /** Error destructor */
56         ~Error () throw () {}
57
58         /** @return error message.  Caller must not free the returned
59          *  value.
60          */
61         char const * what () const throw () {
62                 return _message.c_str ();
63         }
64
65 private:
66         /** error message */
67         std::string _message;
68 };
69
70 class Node;     
71 typedef boost::shared_ptr<cxml::Node> NodePtr;
72 typedef std::list<NodePtr> NodeList;    
73 typedef boost::shared_ptr<const cxml::Node> ConstNodePtr;
74 typedef std::list<std::pair<std::string, std::string> > KeyValueList;
75
76 class Node : public boost::enable_shared_from_this<Node>
77 {
78 public:
79         Node ();
80         Node (xmlpp::Node const *);
81
82         /* A set of methods which look up a child of this node by
83          * its name, and return its contents as some type or other.
84          *
85          * If, for example, this object has been created with
86          * a node named "Fred", we might have the following XML:
87          *
88          * <Fred>
89          *   <Jim>42</Jim>
90          * </Fred>
91          *
92          * string_child ("Jim") would return "42"
93          * number_child<int64_t> ("Jim") would return 42.
94          * ...and so on.
95          *
96          * The methods not marked "optional" will throw an exception
97          * if the child node is not present.  The "optional" methods
98          * will return an empty boost::optional<> in that case.
99          *
100          * All methods will also throw an exception if there is more
101          * than one of the specified child node.
102          */
103
104         std::string string_child (std::string c) const;
105         boost::optional<std::string> optional_string_child (std::string) const;
106
107         bool bool_child (std::string) const;
108         boost::optional<bool> optional_bool_child (std::string) const;
109
110         template <class T>
111         T number_child (std::string c) const
112         {
113                 std::string s = string_child (c);
114                 boost::erase_all (s, " ");
115                 std::stringstream t;
116                 t.imbue (std::locale::classic ());
117                 t << s;
118                 T n;
119                 t >> n;
120                 return n;
121         }
122
123         template <class T>
124         boost::optional<T> optional_number_child (std::string c) const
125         {
126                 boost::optional<std::string> s = optional_string_child (c);
127                 if (!s) {
128                         return boost::optional<T> ();
129                 }
130
131                 std::string t = s.get ();
132                 boost::erase_all (t, " ");
133                 std::stringstream u;
134                 u.imbue (std::locale::classic ());
135                 u << t;
136                 T n;
137                 u >> n;
138                 return n;
139         }
140                 
141         
142         /* These methods look for an attribute of this node, in the
143          * same way as the child methods do.
144          */
145
146         std::string string_attribute (std::string) const;
147         boost::optional<std::string> optional_string_attribute (std::string) const;
148
149         bool bool_attribute (std::string) const;
150         boost::optional<bool> optional_bool_attribute (std::string) const;
151
152         template <class T>
153         T number_attribute (std::string c) const
154         {
155                 std::string s = string_attribute (c);
156                 boost::erase_all (s, " ");
157                 std::stringstream t;
158                 t.imbue (std::locale::classic ());
159                 t << s;
160                 T n;
161                 t >> n;
162                 return n;
163         }
164
165         template <class T>
166         boost::optional<T> optional_number_attribute (std::string c) const
167         {
168                 boost::optional<std::string> s = optional_string_attribute (c);
169                 if (!s) {
170                         return boost::optional<T> ();
171                 }
172
173                 std::string t = s.get ();
174                 boost::erase_all (t, " ");
175                 std::stringstream u;
176                 u.imbue (std::locale::classic ());
177                 u << t;
178                 T n;
179                 u >> n;
180                 return n;
181         }
182
183
184         /* Access to child nodes */
185
186         boost::shared_ptr<Node> child (std::string) const;
187         boost::shared_ptr<Node> optional_child (std::string) const;
188         NodeList children () const;
189         NodeList children (std::string) const;
190
191         
192         /** Add a child node with a given name */
193         NodePtr add_child (std::string name, std::string namespace_prefix = "")
194         {
195                 NodePtr n (new cxml::Node ());
196                 n->set_namespace_prefix (namespace_prefix);
197                 n->set_name (name);
198                 _children.push_back (n);
199                 return n;
200         }
201
202         void set_namespace_declaration (std::string uri, std::string prefix = "");
203
204         KeyValueList namespace_declarations () const {
205                 return _namespace_declarations;
206         }
207
208         void set_content (std::string c) {
209                 _content = c;
210         }
211         
212         /** @return The content of this node */
213         std::string content () const;
214
215         void set_attribute (std::string name, std::string value);
216
217         void set_namespace_prefix (std::string p) {
218                 _namespace_prefix = p;
219         }
220         
221         /** @return namespace prefix of this node */
222         std::string namespace_prefix () const;
223         /** This will mark a child as to be ignored when calling done() */
224         void ignore_child (std::string) const;
225         /** Check whether all children of this Node have been looked up
226          *  or passed to ignore_child().  If not, an exception is thrown.
227          */
228         void done () const;
229         /** Set the name of the node.
230          *  @param n New name.
231          */
232         void set_name (std::string n) {
233                 _name = n;
234         }
235         /** @return Node name */
236         std::string name () const {
237                 return _name;
238         }
239
240         /* We use xmlpp for parsing and writing XML out; these
241            methods help with that.
242         */
243         void read (xmlpp::Node const *);
244         void write (xmlpp::Node *, std::map<cxml::ConstNodePtr, xmlpp::Node*>* mapping = 0) const;
245
246 protected:      
247         NodeList _children;
248         
249 private:
250         std::string _name;
251         std::string _content;
252         std::string _namespace_prefix;
253         KeyValueList _attributes;
254         KeyValueList _namespace_declarations;
255         mutable std::list<std::string> _taken;
256 };
257
258 cxml::NodePtr read_file (boost::filesystem::path);
259 cxml::NodePtr read_stream (std::istream &);
260 cxml::NodePtr read_string (std::string);
261
262 void write_to_xmlpp_document (cxml::ConstNodePtr, xmlpp::Document &, std::map<cxml::ConstNodePtr, xmlpp::Node*>* mapping = 0);
263 void write_to_file (cxml::ConstNodePtr, boost::filesystem::path);
264 void write_to_file_formatted (cxml::ConstNodePtr, boost::filesystem::path);
265 void write_to_stream_formatted (cxml::ConstNodePtr, std::ostream& stream);
266 std::string write_to_string (cxml::ConstNodePtr);
267 std::string write_to_string_formatted (cxml::ConstNodePtr);
268
269 }
270
271 #endif