mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 16:48:06 +02:00
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:
@@ -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 << "]";
|
||||
}
|
||||
|
||||
|
@@ -42,9 +42,19 @@ namespace Poco {
|
||||
namespace JSON {
|
||||
|
||||
|
||||
Handler::Handler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Handler::~Handler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Handler::comma()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::JSON
|
||||
|
@@ -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 << '}';
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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
194
JSON/src/PrintHandler.cpp
Normal 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
|
@@ -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
|
||||
|
Reference in New Issue
Block a user