Add namespace_uri method.
[libcxml.git] / src / cxml.h
1 #ifndef LIBCXML_CXML_H
2 #define LIBCXML_CXML_H
3
4 #include <string>
5 #include <list>
6 #include <stdint.h>
7 #include <boost/shared_ptr.hpp>
8 #include <boost/optional.hpp>
9 #include <boost/lexical_cast.hpp>
10 #include <boost/filesystem.hpp>
11 #include <boost/algorithm/string/erase.hpp>
12 #include <glibmm.h>
13
14 namespace xmlpp {
15         class Node;
16         class DomParser;
17 }
18
19 namespace cxml {
20
21 /** @brief An error */
22 class Error : public std::exception
23 {
24 public:
25         /** Construct an Error exception.
26          *  @param message Error message.
27          */
28         Error (std::string const & message) : _message (message) {}
29
30         /** Error destructor */
31         ~Error () throw () {}
32
33         /** @return error message.  Caller must not free the returned
34          *  value.
35          */
36         char const * what () const throw () {
37                 return _message.c_str ();
38         }
39
40 private:
41         /** error message */
42         std::string _message;
43 };
44
45 /** @brief A wrapper for a xmlpp::Node which simplifies parsing */
46 class Node
47 {
48 public:
49         Node ();
50         
51         /** Construct a Node from an xmlpp::Node.  This class will
52          *  not destroy the xmlpp::Node.
53          *  @param node xmlpp::Node.
54          */
55         Node (xmlpp::Node const * node);
56
57         std::string name () const;
58
59         /* A set of methods which look up a child of this node by
60          * its name, and return its contents as some type or other.
61          *
62          * If, for example, this object has been created with
63          * a node named "Fred", we might have the following XML:
64          *
65          * <Fred>
66          *   <Jim>42</Jim>
67          * </Fred>
68          *
69          * string_child ("Jim") would return "42"
70          * number_child<int64_t> ("Jim") would return 42.
71          * ...and so on.
72          *
73          * The methods not marked "optional" will throw an exception
74          * if the child node is not present.  The "optional" methods
75          * will return an empty boost::optional<> in that case.
76          *
77          * All methods will also throw an exception if there is more
78          * than one of the specified child node.
79          */
80
81         std::string string_child (std::string c) const;
82         boost::optional<std::string> optional_string_child (std::string) const;
83
84         bool bool_child (std::string) const;
85         boost::optional<bool> optional_bool_child (std::string) const;
86
87         template <class T>
88         T number_child (std::string c) const
89         {
90                 std::string s = string_child (c);
91                 boost::erase_all (s, " ");
92                 return boost::lexical_cast<T> (s);
93         }
94
95         template <class T>
96         boost::optional<T> optional_number_child (std::string c) const
97         {
98                 boost::optional<std::string> s = optional_string_child (c);
99                 if (!s) {
100                         return boost::optional<T> ();
101                 }
102
103                 std::string t = s.get ();
104                 boost::erase_all (t, " ");
105                 return boost::optional<T> (boost::lexical_cast<T> (t));
106         }
107                 
108         /** This will mark a child as to be ignored when calling done() */
109         void ignore_child (std::string) const;
110
111         /** Check whether all children of this Node have been looked up
112          *  or passed to ignore_child().  If not, an exception is thrown.
113          */
114         void done () const;
115
116         /* These methods look for an attribute of this node, in the
117          * same way as the child methods do.
118          */
119
120         std::string string_attribute (std::string) const;
121         boost::optional<std::string> optional_string_attribute (std::string) const;
122
123         bool bool_attribute (std::string) const;
124         boost::optional<bool> optional_bool_attribute (std::string) const;
125
126         template <class T>
127         T number_attribute (std::string c) const
128         {
129                 std::string s = string_attribute (c);
130                 boost::erase_all (s, " ");
131                 return boost::lexical_cast<T> (s);
132         }
133
134         template <class T>
135         boost::optional<T> optional_number_attribute (std::string c) const
136         {
137                 boost::optional<std::string> s = optional_string_attribute (c);
138                 if (!s) {
139                         return boost::optional<T> ();
140                 }
141
142                 std::string t = s.get ();
143                 boost::erase_all (t, " ");
144                 return boost::optional<T> (boost::lexical_cast<T> (t));
145         }
146
147         /** @return The content of this node */
148         std::string content () const;
149
150         /** @return namespace URI of this node */
151         std::string namespace_uri () const;
152
153         /** @return namespace prefix of this node */
154         std::string namespace_prefix () const;
155
156         boost::shared_ptr<Node> node_child (std::string) const;
157         boost::shared_ptr<Node> optional_node_child (std::string) const;
158
159         std::list<boost::shared_ptr<Node> > node_children (std::string) const;
160         
161 protected:
162         xmlpp::Node const * _node;
163         
164 private:
165         mutable std::list<Glib::ustring> _taken;
166 };
167
168 class Document : public Node
169 {
170 public:
171         Document (std::string root_name);
172
173         void read_file (boost::filesystem::path);
174         void read_stream (std::istream &);
175         
176         virtual ~Document ();
177
178 private:
179         void take_root_node ();
180         
181         xmlpp::DomParser* _parser;
182         std::string _root_name;
183 };
184
185 }
186
187 #endif