GH #119: JSON::Object holds values in ordered map

- fixed GH #119: JSON::Object holds values in ordered map
- added PrintHandler
- renamed DefaultHandler to ParseHandler
- redefined DefaultHandler as typedef to ParseHandler
This commit is contained in:
aleks-f
2013-03-16 11:33:27 -05:00
parent fe6715890c
commit 42ff341cb9
34 changed files with 1249 additions and 328 deletions

View File

@@ -120,8 +120,10 @@ bool Array::isObject(unsigned int index) const
}
void Array::stringify(std::ostream& out, unsigned int indent) const
void Array::stringify(std::ostream& out, unsigned int indent, int step) const
{
if (step == -1) step = indent;
out << "[";
if (indent > 0) out << std::endl;
@@ -130,15 +132,22 @@ void Array::stringify(std::ostream& out, unsigned int indent) const
{
for(int i = 0; i < indent; i++) out << ' ';
Stringifier::stringify(*it, out, indent);
Stringifier::stringify(*it, out, indent + step, step);
if ( ++it != _values.end() )
{
out << ",";
if ( indent > 0 ) out << std::endl;
if (step > 0) out << '\n';
}
}
if (step > 0) out << '\n';
if (indent >= step) indent -= step;
for (int i = 0; i < indent; i++)
out << ' ';
out << "]";
}

View File

@@ -42,9 +42,19 @@ namespace Poco {
namespace JSON {
Handler::Handler()
{
}
Handler::~Handler()
{
}
void Handler::comma()
{
}
} } // namespace Poco::JSON

View File

@@ -48,20 +48,20 @@ namespace Poco {
namespace JSON {
Object::Object()
Object::Object(bool preserveInsertionOrder): _preserveInsOrder(preserveInsertionOrder)
{
}
Object::Object(const Object& copy) : _values(copy._values)
Object::Object(const Object& copy) : _values(copy._values),
_keys(copy._keys),
_preserveInsOrder(copy._preserveInsOrder)
{
}
Object::~Object()
{
}
@@ -114,27 +114,43 @@ void Object::getNames(std::vector<std::string>& names) const
}
void Object::stringify(std::ostream& out, unsigned int indent) const
void Object::stringify(std::ostream& out, unsigned int indent, int step) const
{
out << '{';
if (step == -1) step = indent;
if (indent > 0) out << std::endl;
if(!_preserveInsOrder)
doStringify(_values, out, indent, step);
else
doStringify(_keys, out, indent, step);
}
for (ValueMap::const_iterator it = _values.begin(); it != _values.end();)
const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
{
ValueMap::const_iterator it = _values.begin();
ValueMap::const_iterator end = _values.end();
for (; it != end; ++it)
{
for(int i = 0; i < indent; i++) out << ' ';
out << '"' << it->first << '"';
out << (( indent > 0 ) ? " : " : ":");
Stringifier::stringify(it->second, out, indent);
if ( ++it != _values.end() ) out << ',';
if ( indent > 0 ) out << std::endl;
if (it->second == **iter) return it->first;
}
throw NotFoundException((*iter)->convert<std::string>());
}
void Object::set(const std::string& key, const Dynamic::Var& value)
{
_values[key] = value;
if (_preserveInsOrder)
{
KeyPtrList::iterator it = _keys.begin();
KeyPtrList::iterator end = _keys.end();
for (; it != end; ++it)
{
if (key == **it) return;
}
_keys.push_back(&_values[key]);
}
out << '}';
}

View File

@@ -1,11 +1,11 @@
//
// DefaultHandler.cpp
// ParseHandler.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: DefaultHandler
// Module: ParseHandler
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
@@ -34,7 +34,7 @@
//
#include "Poco/JSON/DefaultHandler.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/Object.h"
@@ -45,19 +45,20 @@ namespace Poco {
namespace JSON {
DefaultHandler::DefaultHandler() : Handler()
ParseHandler::ParseHandler(bool preserveObjectOrder) : Handler(),
_preserveObjectOrder(preserveObjectOrder)
{
}
DefaultHandler::~DefaultHandler()
ParseHandler::~ParseHandler()
{
}
void DefaultHandler::startObject()
void ParseHandler::startObject()
{
Object::Ptr newObj = new Object();
Object::Ptr newObj = new Object(_preserveObjectOrder);
if ( _stack.empty() ) // The first object
{
@@ -85,13 +86,13 @@ void DefaultHandler::startObject()
}
void DefaultHandler::endObject()
void ParseHandler::endObject()
{
_stack.pop();
}
void DefaultHandler::startArray()
void ParseHandler::startArray()
{
Array::Ptr newArr = new Array();
@@ -121,19 +122,19 @@ void DefaultHandler::startArray()
}
void DefaultHandler::endArray()
void ParseHandler::endArray()
{
_stack.pop();
}
void DefaultHandler::key(const std::string& k)
void ParseHandler::key(const std::string& k)
{
_key = k;
}
void DefaultHandler::setValue(const Var& value)
void ParseHandler::setValue(const Var& value)
{
Var parent = _stack.top();

View File

@@ -67,11 +67,11 @@ public:
bool start(char c, std::istream& istr)
{
if (c == '{'
|| c == '}'
|| c == ']'
|| c == '['
|| c == ','
|| c == ':')
|| c == '}'
|| c == ']'
|| c == '['
|| c == ','
|| c == ':')
{
_value = c;
return true;
@@ -594,6 +594,7 @@ bool Parser::readRow(bool firstCall)
{
if (token->asChar() == ',')
{
_handler->comma();
return true; // Read next row
}
else if (token->asChar() == '}')
@@ -636,46 +637,46 @@ void Parser::readValue(const Token* token)
if (_handler != NULL)
{
#if defined(POCO_HAVE_INT64)
try
{
Int64 value = token->asInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<int>(value));
}
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
UInt64 value = token->asUnsignedInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<unsigned>::max() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<unsigned>(value));
}
}
try
{
Int64 value = token->asInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<int>(value));
}
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
UInt64 value = token->asUnsignedInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<unsigned>::max() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<unsigned>(value));
}
}
#else
try
{
int value = token->asInteger();
_handle->value(value);
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
unsigned value = token->asUnsignedInteger();
_handle->value(value);
}
try
{
int value = token->asInteger();
_handle->value(value);
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
unsigned value = token->asUnsignedInteger();
_handle->value(value);
}
#endif
}
break;
@@ -773,13 +774,16 @@ bool Parser::readElements(bool firstCall)
token = nextToken();
if ( token->is(Token::SEPARATOR_TOKEN) )
if (token->is(Token::SEPARATOR_TOKEN))
{
if (token->asChar() == ']')
return false; // End of array
if (token->asChar() == ',')
{
_handler->comma();
return true;
}
throw JSONException(format("Invalid separator '%c' found. Expecting , or ]", token->asChar()));
}

194
JSON/src/PrintHandler.cpp Normal file
View File

@@ -0,0 +1,194 @@
//
// PrintHandler.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: PrintHandler
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/PrintHandler.h"
#include "Poco/JSON/Stringifier.h"
namespace Poco {
namespace JSON {
PrintHandler::PrintHandler(unsigned indent):
_out(std::cout),
_indent(indent),
_array(false)
{
}
PrintHandler::PrintHandler(std::ostream& out, unsigned indent):
_out(out),
_indent(indent),
_array(false)
{
}
PrintHandler::~PrintHandler()
{
}
const char* PrintHandler::endLine() const
{
if (!printFlat()) return "\n";
else return "";
}
bool PrintHandler::printFlat() const
{
return _indent == JSON_PRINT_FLAT;
}
unsigned PrintHandler::indent()
{
if (!printFlat()) return _indent;
return 0;
}
void PrintHandler::startObject()
{
_out << '{';
_out << endLine();
_tab.append(indent(), ' ');
}
void PrintHandler::endObject()
{
if( _tab.length() >= indent())
_tab.erase(_tab.length() - indent());
_out << endLine() << _tab << '}';
}
void PrintHandler::startArray()
{
_out << '[' << endLine();
_tab.append(indent(), ' ');
_array = true;
}
void PrintHandler::endArray()
{
_tab.erase(_tab.length() - indent());
_out << endLine() << _tab << ']';
_array = false;
}
void PrintHandler::key(const std::string& k)
{
_out << _tab << '"' << k << '"';
if (!printFlat()) _out << ' ';
_out << ':';
if (!printFlat()) _out << ' ';
}
void PrintHandler::null()
{
if (_array) _out << _tab;
_out << "null";
}
void PrintHandler::value(int v)
{
if (_array) _out << _tab;
_out << v;
}
void PrintHandler::value(unsigned v)
{
if (_array) _out << _tab;
_out << v;
}
#if defined(POCO_HAVE_INT64)
void PrintHandler::value(Int64 v)
{
if (_array) _out << _tab;
_out << v;
}
void PrintHandler::value(UInt64 v)
{
if (_array) _out << _tab;
_out << v;
}
#endif
void PrintHandler::value(const std::string& value)
{
if (_array) _out << _tab;
Stringifier::formatString(value, _out);
}
void PrintHandler::value(double d)
{
if (_array) _out << _tab;
_out << d;
}
void PrintHandler::value(bool b)
{
if (_array) _out << _tab;
_out << b;
}
void PrintHandler::comma()
{
_out << ',' << endLine();
}
} } // namespace Poco::JSON

View File

@@ -47,27 +47,29 @@ namespace Poco {
namespace JSON {
void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int indent)
void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int indent, int step, bool preserveInsertionOrder)
{
if (step == -1) step = indent;
if ( any.type() == typeid(Object) )
{
const Object& o = any.extract<Object>();
o.stringify(out, indent == 0 ? 0 : indent + 2);
o.stringify(out, indent == 0 ? 0 : indent, step);
}
else if ( any.type() == typeid(Array) )
{
const Array& a = any.extract<Array>();
a.stringify(out, indent == 0 ? 0 : indent + 2);
a.stringify(out, indent == 0 ? 0 : indent, step);
}
else if ( any.type() == typeid(Object::Ptr) )
{
const Object::Ptr& o = any.extract<Object::Ptr>();
o->stringify(out, indent == 0 ? 0 : indent + 2);
o->stringify(out, indent == 0 ? 0 : indent, step);
}
else if ( any.type() == typeid(Array::Ptr) )
{
const Array::Ptr& a = any.extract<Array::Ptr>();
a->stringify(out, indent == 0 ? 0 : indent + 2);
a->stringify(out, indent == 0 ? 0 : indent, step);
}
else if ( any.isEmpty() )
{
@@ -75,48 +77,8 @@ void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int inde
}
else if ( any.isString() )
{
out << '"';
std::string value = any.convert<std::string>();
for(std::string::const_iterator it = value.begin(); it != value.end(); ++it)
{
switch (*it)
{
case '"':
out << "\\\"";
break;
case '\\':
out << "\\\\";
break;
case '\b':
out << "\\b";
break;
case '\f':
out << "\\f";
break;
case '\n':
out << "\\n";
break;
case '\r':
out << "\\r";
break;
case '\t':
out << "\\t";
break;
default:
{
if ( *it > 0 && *it <= 0x1F )
{
out << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*it);
}
else
{
out << *it;
}
break;
}
}
}
out << '"';
formatString(value, out);
}
else
{
@@ -125,4 +87,49 @@ void Stringifier::stringify(const Var& any, std::ostream& out, unsigned int inde
}
void Stringifier::formatString(const std::string& value, std::ostream& out)
{
out << '"';
for (std::string::const_iterator it = value.begin(); it != value.end(); ++it)
{
switch (*it)
{
case '"':
out << "\\\"";
break;
case '\\':
out << "\\\\";
break;
case '\b':
out << "\\b";
break;
case '\f':
out << "\\f";
break;
case '\n':
out << "\\n";
break;
case '\r':
out << "\\r";
break;
case '\t':
out << "\\t";
break;
default:
{
if ( *it > 0 && *it <= 0x1F )
{
out << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*it);
}
else
{
out << *it;
}
break;
}
}
}
out << '"';
}
} } // Namespace Poco::JSON