Add CCA.xml example as reference for mocking dynamic operation
[anna.git] / include / anna / json / SaxConsumer.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #ifndef anna_json_SaxConsumer_hpp
10 #define anna_json_SaxConsumer_hpp
11
12 #include <iomanip>
13 #include <sstream>
14 #include <stack>
15 #include <anna/json/json.hpp> // nlohmann::json (https://github.com/nlohmann/json)
16 #include <anna/core/util/defines.hpp>
17
18 namespace anna {
19
20 namespace json {
21
22 class SaxConsumer : public nlohmann::json::json_sax_t
23 {
24   char attr_prefix_;
25   int indent_;
26   std::stringstream result_;
27   std::stringstream current_object_;
28   std::stack<std::string> nodes_stack_;
29   std::string key_;
30   bool has_attributes_;
31
32   const std::string & get_top() { return nodes_stack_.top(); }
33
34
35   public:
36
37   SaxConsumer(char attrPrefix = '@') : attr_prefix_(attrPrefix),
38                                            has_attributes_(false),
39                                            indent_(-ANNA_XML_INDENTATION_SPACES) {};
40
41   const std::stringstream & getResult() const { return result_; }
42
43   bool null() override
44   {
45     current_object_ << "<null>";
46     has_attributes_ = true;
47     return true;
48   }
49
50   bool boolean(bool val) override
51   {
52     current_object_ << std::quoted(val ? "true" : "false");
53     has_attributes_ = true;
54     return true;
55   }
56
57   bool number_integer(number_integer_t val) override
58   {
59     current_object_ << std::quoted(std::to_string(val));
60     has_attributes_ = true;
61     return true;
62   }
63
64   bool number_unsigned(number_unsigned_t val) override
65   {
66     current_object_ << std::quoted(std::to_string(val));
67     has_attributes_ = true;
68     return true;
69   }
70
71   bool number_float(number_float_t val, const string_t& s) override
72   {
73     current_object_ << std::quoted(s);
74     has_attributes_ = true;
75     return true;
76   }
77
78   bool string(string_t& val) override
79   {
80     current_object_ << std::quoted(val);
81     has_attributes_ = true;
82     return true;
83   }
84
85   bool start_object(std::size_t elements) override
86   {
87     if (key_ == "") return true; // global object condition (first start object)
88     nodes_stack_.push(key_); // push on starts
89     indent_ += ANNA_XML_INDENTATION_SPACES; // increase indentation on object start
90
91     if (indent_ != 0) {
92       // New object when previous hadn't attributes:
93       if (current_object_.str().empty() && !has_attributes_) result_ <<">";
94       result_ << "\n";
95     }
96     result_ << std::string(indent_, ' ') << "<" << get_top();
97
98     has_attributes_ = false;
99     return true;
100   }
101
102   bool end_object() override
103   {
104     if (indent_ < 0) return true;
105     if (current_object_.str().empty()) {
106       result_ << "\n" << std::string(indent_, ' ') << "</" << get_top() << ">";
107     }
108     else {
109       result_ << current_object_.str() << "/>";
110       current_object_.str("");
111     }
112
113     nodes_stack_.pop(); // pop on ends
114     indent_ -= ANNA_XML_INDENTATION_SPACES; // decrease indentation on object end
115     return true;
116   }
117
118   bool start_array(std::size_t elements) override
119   {
120     nodes_stack_.push(key_); // push on starts
121
122     result_ << current_object_.str();
123
124     current_object_.str("");
125     has_attributes_ = false;
126
127     return true;
128   }
129
130   bool end_array() override
131   {
132     nodes_stack_.pop(); // pop on ends
133     return true;
134   }
135
136   bool key(string_t& val) override
137   {
138     if (val[0] != attr_prefix_) {
139       key_ = val;
140     }
141     else {
142       current_object_ << " " << val.substr(1) << "=";
143     }
144     return true;
145   }
146
147   bool parse_error(std::size_t position, const std::string& last_token, const nlohmann::json::exception& ex) override
148   {
149     result_ << std::string(ex.what());
150     return false;
151   }
152 };
153
154 }
155 }
156
157 #endif