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 <boost/shared_ptr.hpp>
24 #include <boost/optional.hpp>
25 #include <boost/filesystem.hpp>
26 #include <boost/algorithm/string/erase.hpp>
27 #include <stdint.h>
28 #include <string>
29 #include <sstream>
30 #include <list>
31
32 /* Hack for OS X compile failure; see https://bugs.launchpad.net/hugin/+bug/910160 */
33 #ifdef check
34 #undef check
35 #endif
36
37 namespace xmlpp {
38         class Node;
39         class DomParser;
40 }
41
42 namespace cxml {
43
44 /** @brief An error */
45 class Error : public std::exception
46 {
47 public:
48         /** Construct an Error exception.
49          *  @param message Error message.
50          */
51         Error (std::string const & message) : _message (message) {}
52
53         /** Error destructor */
54         ~Error () throw () {}
55
56         /** @return error message.  Caller must not free the returned
57          *  value.
58          */
59         char const * what () const throw () {
60                 return _message.c_str ();
61         }
62
63 private:
64         /** error message */
65         std::string _message;
66 };
67
68 /** @brief A wrapper for a xmlpp::Node which simplifies parsing */
69 class Node
70 {
71 public:
72         Node ();
73
74         /** Construct a Node from an xmlpp::Node.  This class will
75          *  not destroy the xmlpp::Node.
76          *  @param node xmlpp::Node.
77          */
78         Node (xmlpp::Node* node);
79
80         std::string name () 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         /** This will mark a child as to be ignored when calling done() */
142         void ignore_child (std::string) const;
143
144         /** Check whether all children of this Node have been looked up
145          *  or passed to ignore_child().  If not, an exception is thrown.
146          */
147         void done () const;
148
149         /* These methods look for an attribute of this node, in the
150          * same way as the child methods do.
151          */
152
153         std::string string_attribute (std::string) const;
154         boost::optional<std::string> optional_string_attribute (std::string) const;
155
156         bool bool_attribute (std::string) const;
157         boost::optional<bool> optional_bool_attribute (std::string) const;
158
159         template <class T>
160         T number_attribute (std::string c) const
161         {
162                 std::string s = string_attribute (c);
163                 boost::erase_all (s, " ");
164                 std::stringstream t;
165                 t.imbue (std::locale::classic ());
166                 t << s;
167                 T n;
168                 t >> n;
169                 return n;
170         }
171
172         template <class T>
173         boost::optional<T> optional_number_attribute (std::string c) const
174         {
175                 boost::optional<std::string> s = optional_string_attribute (c);
176                 if (!s) {
177                         return boost::optional<T> ();
178                 }
179
180                 std::string t = s.get ();
181                 boost::erase_all (t, " ");
182                 std::stringstream u;
183                 u.imbue (std::locale::classic ());
184                 u << t;
185                 T n;
186                 u >> n;
187                 return n;
188         }
189
190         /** @return The content of this node */
191         std::string content () const;
192
193         /** @return namespace URI of this node */
194         std::string namespace_uri () const;
195
196         /** @return namespace prefix of this node */
197         std::string namespace_prefix () const;
198
199         boost::shared_ptr<Node> node_child (std::string) const;
200         boost::shared_ptr<Node> optional_node_child (std::string) const;
201
202         std::list<boost::shared_ptr<Node> > node_children (std::string) const;
203
204         xmlpp::Node* node () const {
205                 return _node;
206         }
207
208 protected:
209         xmlpp::Node* _node;
210
211 private:
212         mutable std::list<std::string> _taken;
213 };
214
215 typedef boost::shared_ptr<cxml::Node> NodePtr;
216 typedef boost::shared_ptr<const cxml::Node> ConstNodePtr;
217
218 class Document : public Node
219 {
220 public:
221         Document ();
222         Document (std::string root_name);
223         Document (std::string root_name, boost::filesystem::path);
224
225         virtual ~Document ();
226
227         void read_file (boost::filesystem::path);
228         void read_stream (std::istream &);
229         void read_string (std::string);
230
231         std::string root_name () const {
232                 return _root_name;
233         }
234
235 private:
236         void take_root_node ();
237
238         xmlpp::DomParser* _parser;
239         std::string _root_name;
240 };
241
242 }
243
244 #endif