diff --git a/jsonxx.cc b/jsonxx.cc index 80c847a..fb26a49 100644 --- a/jsonxx.cc +++ b/jsonxx.cc @@ -7,6 +7,7 @@ #include "jsonxx.h" +#include #include #include #include @@ -310,6 +311,8 @@ bool Object::parse(std::istream& input, Object& object) { // TODO(hjiang): Add an option to allow duplicated keys? if (object.value_map_.find(key) == object.value_map_.end()) { object.value_map_[key] = v; + if (keys_are_ordered()) + object.key_set_.push_back(key); } else { if (parser_is_permissive()) { delete object.value_map_[key]; @@ -503,16 +506,30 @@ std::ostream& operator<<(std::ostream& stream, const jsonxx::Array& v) { std::ostream& operator<<(std::ostream& stream, const jsonxx::Object& v) { stream << "{"; - jsonxx::Object::container::const_iterator - it = v.kv_map().begin(), - end = v.kv_map().end(); - while (it != end) { - jsonxx::stream_string(stream, it->first); - stream << ": " << *(it->second); - ++it; - if (it != end) { - stream << ", "; - } + if (jsonxx::keys_are_ordered()) { + const std::vector& keys = v.keys(); + std::string last = keys[keys.size()-1]; + const std::map& kv_map = v.kv_map(); + for (std::string key : keys) { + printf(" %s\n", key.c_str()); + jsonxx::stream_string(stream, key); + stream << ": " << *(kv_map.at(key)); + if (key != last) { + stream << ", "; + } + } + } else { + jsonxx::Object::container::const_iterator + it = v.kv_map().begin(), + end = v.kv_map().end(); + while (it != end) { + jsonxx::stream_string(stream, it->first); + stream << ": " << *(it->second); + ++it; + if (it != end) { + stream << ", "; + } + } } return stream << "}"; } @@ -603,9 +620,15 @@ namespace json { case jsonxx::Value::OBJECT_: ss << "{\n"; - for(Object::container::const_iterator it=t.object_value_->kv_map().begin(), - end = t.object_value_->kv_map().end(); it != end ; ++it) - ss << tag( format, depth+1, it->first, *it->second ); + if (keys_are_ordered()) { + const std::map& kv_map = t.object_value_->kv_map(); + for(std::string key : t.object_value_->keys()) + ss << tag( format, depth+1, key, *kv_map.at(key) ); + } else { + for(Object::container::const_iterator it=t.object_value_->kv_map().begin(), + end = t.object_value_->kv_map().end(); it != end ; ++it) + ss << tag( format, depth+1, it->first, *it->second ); + } return remove_last_comma( ss.str() ) + tab + "}" ",\n"; case jsonxx::Value::NUMBER_: @@ -788,13 +811,20 @@ std::string tag( unsigned format, unsigned depth, const std::string &name, const + ss.str() + close_tag( format, 's', name ) + '\n'; - case jsonxx::Value::OBJECT_: - for(Object::container::const_iterator it=t.object_value_->kv_map().begin(), - end = t.object_value_->kv_map().end(); it != end ; ++it) - ss << tag( format, depth+1, it->first, *it->second ); + case jsonxx::Value::OBJECT_: { + if (keys_are_ordered()) { + const std::map& kv_map = t.object_value_->kv_map(); + for(std::string key : t.object_value_->keys()) + ss << tag( format, depth+1, key, *kv_map.at(key) ); + } else { + for(Object::container::const_iterator it=t.object_value_->kv_map().begin(), + end = t.object_value_->kv_map().end(); it != end ; ++it) + ss << tag( format, depth+1, it->first, *it->second ); + } return tab + open_tag( format, 'o', name, attr ) + '\n' + ss.str() + tab + close_tag( format, 'o', name ) + '\n'; + } case jsonxx::Value::NUMBER_: // max precision @@ -999,15 +1029,29 @@ void Object::import( const Object &other ) { odd.clear(); if (this != &other) { // default - container::const_iterator - it = other.value_map_.begin(), - end = other.value_map_.end(); - for (/**/ ; it != end ; ++it) { - container::iterator found = value_map_.find(it->first); - if( found != value_map_.end() ) { - delete found->second; + if (keys_are_ordered()) { + const std::vector& keys = other.keys(); + const std::map& kv_map = other.kv_map(); + for (std::string key : keys) { + container::iterator found = value_map_.find(key); + if( found != value_map_.end() ) { + delete found->second; + } else if (keys_are_ordered()) { + key_set_.push_back(key); + } + value_map_[ key ] = new Value( *kv_map.at(key) ); + } + } else { + container::const_iterator + it = other.value_map_.begin(), + end = other.value_map_.end(); + for (/**/ ; it != end ; ++it) { + container::iterator found = value_map_.find(it->first); + if( found != value_map_.end() ) { + delete found->second; + } + value_map_[ it->first ] = new Value( *it->second ); } - value_map_[ it->first ] = new Value( *it->second ); } } else { // recursion is supported here @@ -1019,6 +1063,8 @@ void Object::import( const std::string &key, const Value &value ) { container::iterator found = value_map_.find(key); if( found != value_map_.end() ) { delete found->second; + } else if (keys_are_ordered()) { + key_set_.push_back(key); } value_map_[ key ] = new Value( value ); } @@ -1050,6 +1096,9 @@ size_t Object::size() const { bool Object::empty() const { return value_map_.size() == 0; } +const std::vector &Object::keys() const { + return key_set_; +} const std::map &Object::kv_map() const { return value_map_; } @@ -1062,6 +1111,7 @@ void Object::reset() { delete i->second; } value_map_.clear(); + key_set_.clear(); } bool Object::parse(std::istream &input) { return parse(input,*this); diff --git a/jsonxx.h b/jsonxx.h index 757a4dd..1f0668e 100644 --- a/jsonxx.h +++ b/jsonxx.h @@ -62,7 +62,8 @@ enum Settings { // values Parser = Permissive, // permissive or strict parsing UnquotedKeys = Disabled, // support of unquoted keys - Assertions = Enabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds) + Assertions = Enabled, // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds) + OrderedKeys = Enabled }; #ifdef _MSC_VER @@ -72,6 +73,7 @@ enum Settings { inline bool parser_is_strict() { return Parser == Strict; } inline bool parser_is_permissive() { return Parser == Permissive; } inline bool unquoted_keys_are_enabled() { return UnquotedKeys == Enabled; } +inline bool keys_are_ordered() { return OrderedKeys == Enabled; } #ifdef _MSC_VER #pragma warning(pop) #endif @@ -133,6 +135,7 @@ class Object { size_t size() const; bool empty() const; + const std::vector& keys() const; const std::map& kv_map() const; std::string json() const; std::string xml( unsigned format = JSONx, const std::string &header = std::string(), const std::string &attrib = std::string() ) const; @@ -159,6 +162,7 @@ class Object { protected: static bool parse(std::istream& input, Object& object); container value_map_; + std::vector key_set_; std::string odd; };