class SaxConsumer : public nlohmann::json::json_sax_t
{
+ char attr_prefix_;
int indent_;
- bool started_, last_was_start_, last_was_array_;
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), last_was_start_(false), last_was_array_(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>";
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool boolean(bool val) override
{
current_object_ << std::quoted(val ? "true" : "false");
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool number_integer(number_integer_t val) override
{
current_object_ << std::quoted(std::to_string(val));
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool number_unsigned(number_unsigned_t val) override
{
current_object_ << std::quoted(std::to_string(val));
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool number_float(number_float_t val, const string_t& s) override
{
current_object_ << std::quoted(s);
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool string(string_t& val) override
{
current_object_ << std::quoted(val);
- last_was_start_ = false;
+ has_attributes_ = true;
return true;
}
bool start_object(std::size_t elements) override
{
- if (!started_) { started_ = true ; return true; }
- indent_ += ANNA_XML_INDENTATION_SPACES;
- if (last_was_start_) result_ << ">\n";
- last_was_start_ = true;
- if (!last_was_array_) nodes_stack_.push(key_);
- result_ << std::string(indent_, ' ') << "<" << nodes_stack_.top();
- if (last_was_array_) nodes_stack_.push(key_);
- last_was_array_ = false;
+ 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;
- if (close == "") result_ << std::string(indent_, ' ') << "</" << nodes_stack_.top() << ">";
- indent_ -= ANNA_XML_INDENTATION_SPACES;
- result_ << "\n";
- current_object_.str("");
- nodes_stack_.pop();
+ 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
{
- nodes_stack_.push(key_);
- 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
{
- nodes_stack_.pop();
- last_was_array_ = true;
+ nodes_stack_.pop(); // pop on ends
return true;
}
bool key(string_t& val) override
{
- if (val[0] != '@') {
+ if (val[0] != attr_prefix_) {
key_ = val;
}
else {