#include <iomanip>
#include <sstream>
#include <stack>
-#include <anna/json/json.hpp> // nlohmann::json
+#include <anna/json/json.hpp> // nlohmann::json (https://github.com/nlohmann/json)
#include <anna/core/util/defines.hpp>
namespace anna {
class SaxConsumer : public nlohmann::json::json_sax_t
{
+ char attr_prefix_;
int indent_;
- bool started_;
std::stringstream result_;
std::stringstream current_object_;
std::stack<std::string> nodes_stack_;
+ std::string key_;
+ bool has_attributes_;
+
+ const std::string & get_top() { return nodes_stack_.top(); }
+
public:
- SaxConsumer() : started_(false), indent_(-ANNA_XML_INDENTATION_SPACES) {}
+ SaxConsumer(char attrPrefix = '@') : attr_prefix_(attrPrefix),
+ has_attributes_(false),
+ indent_(-ANNA_XML_INDENTATION_SPACES) {};
const std::stringstream & getResult() const { return result_; }
bool null() override
{
current_object_ << "<null>";
+ has_attributes_ = true;
return true;
}
bool boolean(bool val) override
{
current_object_ << std::quoted(val ? "true" : "false");
+ has_attributes_ = true;
return true;
}
bool number_integer(number_integer_t val) override
{
current_object_ << std::quoted(std::to_string(val));
+ has_attributes_ = true;
return true;
}
bool number_unsigned(number_unsigned_t val) override
{
current_object_ << std::quoted(std::to_string(val));
+ has_attributes_ = true;
return true;
}
bool number_float(number_float_t val, const string_t& s) override
{
current_object_ << std::quoted(s);
+ has_attributes_ = true;
return true;
}
bool string(string_t& val) override
{
current_object_ << std::quoted(val);
+ has_attributes_ = true;
return true;
}
bool start_object(std::size_t elements) override
{
- if (!started_) { started_ = true ; return true; } // ignore first start object (which is whole json object {)
- indent_ += ANNA_XML_INDENTATION_SPACES;
- result_ << std::string(indent_, ' ') << "<" << nodes_stack_.top();
+ if (key_ == "") return true; // global object condition (first start object)
+ nodes_stack_.push(key_); // push on starts
+ indent_ += ANNA_XML_INDENTATION_SPACES; // increase indentation on object start
+
+ if (indent_ != 0) {
+ // New object when previous hadn't attributes:
+ if (current_object_.str().empty() && !has_attributes_) result_ <<">";
+ result_ << "\n";
+ }
+ result_ << std::string(indent_, ' ') << "<" << get_top();
+
+ has_attributes_ = false;
return true;
}
bool end_object() override
{
- std::string close = "/>";
- if (current_object_.str().empty()) close = "";
- result_ << current_object_.str() << close;
if (indent_ < 0) return true;
- indent_ -= ANNA_XML_INDENTATION_SPACES;
- if (close == "") result_ << "</" << nodes_stack_.top() << ">";
- result_ << "\n";
- current_object_.str("");
+ if (current_object_.str().empty()) {
+ result_ << "\n" << std::string(indent_, ' ') << "</" << get_top() << ">";
+ }
+ else {
+ result_ << current_object_.str() << "/>";
+ current_object_.str("");
+ }
+
+ nodes_stack_.pop(); // pop on ends
+ indent_ -= ANNA_XML_INDENTATION_SPACES; // decrease indentation on object end
return true;
}
bool start_array(std::size_t elements) override
{
- result_ << current_object_.str() << ">\n";
+ nodes_stack_.push(key_); // push on starts
+
+ result_ << current_object_.str();
+
current_object_.str("");
+ has_attributes_ = false;
+
return true;
}
bool end_array() override
{
- result_ << std::string(indent_, ' ');
- nodes_stack_.pop();
+ nodes_stack_.pop(); // pop on ends
return true;
}
bool key(string_t& val) override
{
- if (val[0] != '@') {
- nodes_stack_.push(val);
+ if (val[0] != attr_prefix_) {
+ key_ = val;
}
else {
current_object_ << " " << val.substr(1) << "=";