libcxml
cxml.h
1 /*
2  Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3 
4  This file is part of libcxml.
5 
6  libcxml is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  libcxml is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with libcxml. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #ifndef LIBCXML_CXML_H
22 #define LIBCXML_CXML_H
23 
24 #include <glibmm/ustring.h>
25 #include <boost/optional.hpp>
26 #include <boost/filesystem.hpp>
27 #include <boost/algorithm/string/erase.hpp>
28 #include <exception>
29 #include <memory>
30 #include <string>
31 #include <vector>
32 
33 /* Hack for OS X compile failure; see https://bugs.launchpad.net/hugin/+bug/910160 */
34 #ifdef check
35 #undef check
36 #endif
37 
38 namespace xmlpp {
39  class DomParser;
40  class Element;
41  class Node;
42 }
43 
44 namespace cxml {
45 
47 class Error : public std::exception
48 {
49 public:
53  Error (std::string const & message) : _message (message) {}
54 
56  ~Error () throw () {}
57 
61  char const * what () const noexcept override {
62  return _message.c_str ();
63  }
64 
65 private:
67  std::string _message;
68 };
69 
73 template <typename P, typename Q>
74 P
75 raw_convert (Q)
76 {
77  /* We can't write a generic version of raw_convert; all required
78  versions must be specialised.
79  */
80  BOOST_STATIC_ASSERT (sizeof(Q) == 0);
81 }
82 
83 template <>
84 int
85 raw_convert (std::string v);
86 
87 template <>
88 unsigned int
89 raw_convert (std::string v);
90 
91 template <>
92 long int
93 raw_convert (std::string v);
94 
95 template <>
96 long unsigned int
97 raw_convert (std::string v);
98 
99 template <>
100 long long
101 raw_convert (std::string v);
102 
103 template <>
104 long long unsigned
105 raw_convert (std::string v);
106 
107 template <>
108 float
109 raw_convert (std::string v);
110 
111 template <>
112 double
113 raw_convert (std::string v);
114 
116 class Node
117 {
118 public:
119  Node ();
120 
125  Node (xmlpp::Node* node);
126 
127  std::string name () const;
128 
129  /* A set of methods which look up a child of this node by
130  * its name, and return its contents as some type or other.
131  *
132  * If, for example, this object has been created with
133  * a node named "Fred", we might have the following XML:
134  *
135  * <Fred>
136  * <Jim>42</Jim>
137  * </Fred>
138  *
139  * string_child ("Jim") would return "42"
140  * number_child<int64_t> ("Jim") would return 42.
141  * ...and so on.
142  *
143  * The methods not marked "optional" will throw an exception
144  * if the child node is not present. The "optional" methods
145  * will return an empty boost::optional<> in that case.
146  *
147  * All methods will also throw an exception if there is more
148  * than one of the specified child node.
149  */
150 
151  std::string string_child (std::string c) const;
152  boost::optional<std::string> optional_string_child (std::string) const;
153 
154  bool bool_child (std::string) const;
155  boost::optional<bool> optional_bool_child (std::string) const;
156 
157  template <class T>
158  T number_child (std::string c) const
159  {
160  auto s = string_child (c);
161  boost::erase_all (s, " ");
162  return raw_convert<T> (s);
163  }
164 
165  template <class T>
166  boost::optional<T> optional_number_child (std::string c) const
167  {
168  auto s = optional_string_child (c);
169  if (!s) {
170  return {};
171  }
172 
173  auto t = s.get ();
174  boost::erase_all (t, " ");
175  return raw_convert<T> (t);
176  }
177 
179  void ignore_child (std::string) const;
180 
184  void done () const;
185 
186  /* These methods look for an attribute of this node, in the
187  * same way as the child methods do.
188  */
189 
190  std::string string_attribute (std::string) const;
191  boost::optional<std::string> optional_string_attribute (std::string) const;
192 
193  bool bool_attribute (std::string) const;
194  boost::optional<bool> optional_bool_attribute (std::string) const;
195 
196  template <class T>
197  T number_attribute (std::string c) const
198  {
199  std::string s = string_attribute (c);
200  boost::erase_all (s, " ");
201  return raw_convert<T> (s);
202  }
203 
204  template <class T>
205  boost::optional<T> optional_number_attribute (std::string c) const
206  {
207  auto s = optional_string_attribute (c);
208  if (!s) {
209  return boost::optional<T> ();
210  }
211 
212  auto t = s.get ();
213  boost::erase_all (t, " ");
214  return raw_convert<T> (t);
215  }
216 
218  std::string content () const;
219 
221  std::string namespace_uri () const;
222 
224  std::string namespace_prefix () const;
225 
226  std::shared_ptr<Node> node_child (std::string) const;
227  std::shared_ptr<Node> optional_node_child (std::string) const;
228 
229  std::vector<std::shared_ptr<Node>> node_children () const;
230  std::vector<std::shared_ptr<Node>> node_children (std::string) const;
231 
232  xmlpp::Node* node () const {
233  return _node;
234  }
235 
236  bool is_text() const;
237 
238 protected:
239  xmlpp::Node* _node;
240 
241 private:
242  mutable std::vector<Glib::ustring> _taken;
243 };
244 
245 typedef std::shared_ptr<cxml::Node> NodePtr;
246 typedef std::shared_ptr<const cxml::Node> ConstNodePtr;
247 
248 class Document : public Node
249 {
250 public:
251  Document ();
252  explicit Document(std::string root_name);
253  Document (std::string root_name, boost::filesystem::path);
254 
255  Document (Document const&) = delete;
256  Document& operator= (Document const&) = delete;
257 
258  virtual ~Document ();
259 
260  void read_file (boost::filesystem::path);
261  void read_string (std::string);
262 
263  std::string root_name () const {
264  return _root_name;
265  }
266 
267 private:
268  void take_root_node ();
269 
270  xmlpp::DomParser* _parser;
271  std::string _root_name;
272 };
273 
274 
275 xmlpp::Element* add_child(xmlpp::Element* parent, std::string const& name, std::string const& ns_prefix = {});
276 void add_text_child(xmlpp::Element* parent, std::string const& name, std::string const& text);
277 
278 
279 }
280 
281 #endif
Definition: cxml.h:249
An error.
Definition: cxml.h:48
Error(std::string const &message)
Definition: cxml.h:53
char const * what() const noexcept override
Definition: cxml.h:61
~Error()
Definition: cxml.h:56
A wrapper for a xmlpp::Node which simplifies parsing.
Definition: cxml.h:117
void ignore_child(std::string) const
Definition: cxml.cc:162
std::string namespace_prefix() const
Definition: cxml.cc:249
std::string content() const
Definition: cxml.cc:228
void done() const
Definition: cxml.cc:218
std::string namespace_uri() const
Definition: cxml.cc:243