Initial.
[libcxml.git] / src / cxml.cc
1 #include <sstream>
2 #include <iostream>
3 #include <boost/lexical_cast.hpp>
4 #include <boost/filesystem.hpp>
5 #include <boost/algorithm/string.hpp>
6 #include <libxml++/libxml++.h>
7 #include "cxml.h"
8
9 using namespace std;
10 using namespace boost;
11
12 cxml::Node::Node ()
13         : _node (0)
14 {
15
16 }
17
18 cxml::Node::Node (xmlpp::Node const * node)
19         : _node (node)
20 {
21
22 }
23
24 shared_ptr<cxml::Node>
25 cxml::Node::node_child (string name)
26 {
27         list<shared_ptr<cxml::Node> > n = node_children (name);
28         if (n.size() > 1) {
29                 throw cxml::Error ("duplicate XML tag " + name);
30         } else if (n.empty ()) {
31                 throw cxml::Error ("missing XML tag " + name + " in " + _node->get_name());
32         }
33         
34         return n.front ();
35 }
36
37 list<shared_ptr<cxml::Node> >
38 cxml::Node::node_children (string name)
39 {
40         /* XXX: using find / get_path should work here, but I can't follow
41            how get_path works.
42         */
43
44         xmlpp::Node::NodeList c = _node->get_children ();
45         
46         list<shared_ptr<cxml::Node> > n;
47         for (xmlpp::Node::NodeList::iterator i = c.begin (); i != c.end(); ++i) {
48                 if ((*i)->get_name() == name) {
49                         n.push_back (shared_ptr<Node> (new Node (*i)));
50                 }
51         }
52         
53         _taken.push_back (name);
54         return n;
55 }
56
57 string
58 cxml::Node::string_child (string c)
59 {
60         return node_child(c)->content ();
61 }
62
63 optional<string>
64 cxml::Node::optional_string_child (string c)
65 {
66         list<shared_ptr<Node> > nodes = node_children (c);
67         if (nodes.size() > 1) {
68                 throw cxml::Error ("duplicate XML tag " + c);
69         }
70
71         if (nodes.empty ()) {
72                 return optional<string> ();
73         }
74
75         return nodes.front()->content();
76 }
77
78 bool
79 cxml::Node::bool_child (string c)
80 {
81         string const s = string_child (c);
82         return (s == "1" || s == "yes");
83 }
84
85 optional<bool>
86 cxml::Node::optional_bool_child (string c)
87 {
88         optional<string> s = optional_string_child (c);
89         if (!s) {
90                 return optional<bool> ();
91         }
92         
93         return (s.get() == "1" || s.get() == "yes");
94 }
95
96 void
97 cxml::Node::ignore_child (string name)
98 {
99         _taken.push_back (name);
100 }
101
102 string
103 cxml::Node::string_attribute (string name)
104 {
105         xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
106         if (!e) {
107                 throw cxml::Error ("missing attribute");
108         }
109         
110         xmlpp::Attribute* a = e->get_attribute (name);
111         if (!a) {
112                 throw cxml::Error ("missing attribute");
113         }
114
115         return a->get_value ();
116 }
117
118 optional<string>
119 cxml::Node::optional_string_attribute (string name)
120 {
121         xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
122         if (!e) {
123                 return optional<string> ();
124         }
125         
126         xmlpp::Attribute* a = e->get_attribute (name);
127         if (!a) {
128                 return optional<string> ();
129         }
130
131         return string (a->get_value ());
132 }
133
134 bool
135 cxml::Node::bool_attribute (string name)
136 {
137         string const s = string_attribute (name);
138         return (s == "1" || s == "yes");
139 }
140
141 optional<bool>
142 cxml::Node::optional_bool_attribute (string name)
143 {
144         optional<string> s = optional_string_attribute (name);
145         if (!s) {
146                 return optional<bool> ();
147         }
148
149         return (s.get() == "1" || s.get() == "yes");
150 }
151
152 void
153 cxml::Node::done ()
154 {
155         xmlpp::Node::NodeList c = _node->get_children ();
156         for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) {
157                 if (dynamic_cast<xmlpp::Element *> (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) {
158                         throw cxml::Error ("unexpected XML node " + (*i)->get_name());
159                 }
160         }
161 }
162
163 string
164 cxml::Node::content ()
165 {
166         string content;
167         
168         xmlpp::Node::NodeList c = _node->get_children ();
169         for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) {
170                 xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i);
171                 if (v) {
172                         content += v->get_content ();
173                 }
174         }
175
176         return content;
177 }
178
179 cxml::File::File (string file, string root_name)
180 {
181         if (!filesystem::exists (file)) {
182                 throw cxml::Error ("XML file does not exist");
183         }
184         
185         _parser = new xmlpp::DomParser;
186         _parser->parse_file (file);
187         if (!_parser) {
188                 throw cxml::Error ("could not parse XML");
189         }
190
191         _node = _parser->get_document()->get_root_node ();
192         if (_node->get_name() != root_name) {
193                 throw cxml::Error ("unrecognised root node");
194         }
195 }
196
197 cxml::File::~File ()
198 {
199         delete _parser;
200 }