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

@ -23,6 +23,10 @@ Release 1.5.2 (2013-03-??)
- added ListMap (map-like container with preserving insertion order)
- MailMessage: attachments saving support and consistent read/write
- fixed GH #124: Possibile buffer overrun in Foundation/EventLogChannel
- fixed GH #119: JSON::Object holds values in ordered map
- added PrintHandler
- renamed DefaultHandler to ParseHandler
- redefined DefaultHandler as typedef to ParseHandler
Release 1.5.1 (2013-01-11)
==========================

View File

@ -247,4 +247,11 @@
#endif
#if defined(POCO_OS_FAMILY_WINDOWS)
#define POCO_DEFAULT_NEWLINE_CHARS "\r\n"
#else
#define POCO_DEFAULT_NEWLINE_CHARS "\n"
#endif
#endif // Foundation_Platform_INCLUDED

View File

@ -40,13 +40,6 @@
namespace Poco {
#if defined(_WIN32)
#define POCO_DEFAULT_NEWLINE_CHARS "\r\n"
#else
#define POCO_DEFAULT_NEWLINE_CHARS "\n"
#endif
const std::string LineEnding::NEWLINE_DEFAULT(POCO_DEFAULT_NEWLINE_CHARS);
const std::string LineEnding::NEWLINE_CR("\r");
const std::string LineEnding::NEWLINE_CRLF("\r\n");

View File

@ -433,7 +433,7 @@
<File
RelativePath=".\src\Array.cpp"/>
<File
RelativePath=".\src\DefaultHandler.cpp"/>
RelativePath=".\src\ParseHandler.cpp"/>
<File
RelativePath=".\src\Handler.cpp"/>
<File
@ -442,6 +442,8 @@
RelativePath=".\src\Object.cpp"/>
<File
RelativePath=".\src\Parser.cpp"/>
<File
RelativePath=".\src\PrintHandler.cpp"/>
<File
RelativePath=".\src\Query.cpp"/>
<File
@ -467,6 +469,10 @@
RelativePath=".\include\Poco\JSON\Object.h"/>
<File
RelativePath=".\include\Poco\JSON\Parser.h"/>
<File
RelativePath=".\include\Poco\JSON\ParseHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\PrintHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\Query.h"/>
<File

View File

@ -273,7 +273,9 @@
<ClInclude Include="include\Poco\JSON\JSON.h" />
<ClInclude Include="include\Poco\JSON\JSONException.h" />
<ClInclude Include="include\Poco\JSON\Object.h" />
<ClInclude Include="include\Poco\JSON\ParseHandler.h" />
<ClInclude Include="include\Poco\JSON\Parser.h" />
<ClInclude Include="include\Poco\JSON\PrintHandler.h" />
<ClInclude Include="include\Poco\JSON\Query.h" />
<ClInclude Include="include\Poco\JSON\Stringifier.h" />
<ClInclude Include="include\Poco\JSON\Template.h" />
@ -281,11 +283,12 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Array.cpp" />
<ClCompile Include="src\DefaultHandler.cpp" />
<ClCompile Include="src\ParseHandler.cpp" />
<ClCompile Include="src\Handler.cpp" />
<ClCompile Include="src\JSONException.cpp" />
<ClCompile Include="src\Object.cpp" />
<ClCompile Include="src\Parser.cpp" />
<ClCompile Include="src\PrintHandler.cpp" />
<ClCompile Include="src\Query.cpp" />
<ClCompile Include="src\Stringifier.cpp" />
<ClCompile Include="src\Template.cpp" />

View File

@ -42,14 +42,17 @@
<ClInclude Include="include\Poco\JSON\TemplateCache.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\PrintHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\ParseHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\DefaultHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -74,5 +77,11 @@
<ClCompile Include="src\TemplateCache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PrintHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ParseHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -274,11 +274,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\Array.cpp"/>
<ClCompile Include="src\DefaultHandler.cpp"/>
<ClCompile Include="src\ParseHandler.cpp"/>
<ClCompile Include="src\Handler.cpp"/>
<ClCompile Include="src\JSONException.cpp"/>
<ClCompile Include="src\Object.cpp"/>
<ClCompile Include="src\Parser.cpp"/>
<ClCompile Include="src\PrintHandler.cpp"/>
<ClCompile Include="src\Query.cpp"/>
<ClCompile Include="src\Stringifier.cpp"/>
<ClCompile Include="src\Template.cpp"/>
@ -292,6 +293,8 @@
<ClInclude Include="include\Poco\JSON\JSONException.h"/>
<ClInclude Include="include\Poco\JSON\Object.h"/>
<ClInclude Include="include\Poco\JSON\Parser.h"/>
<ClInclude Include="include\Poco\JSON\ParseHandler.h"/>
<ClInclude Include="include\Poco\JSON\PrintHandler.h"/>
<ClInclude Include="include\Poco\JSON\Query.h"/>
<ClInclude Include="include\Poco\JSON\Stringifier.h"/>
<ClInclude Include="include\Poco\JSON\Template.h"/>

View File

@ -12,7 +12,7 @@
<ClCompile Include="src\Array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\DefaultHandler.cpp">
<ClCompile Include="src\ParseHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Handler.cpp">
@ -27,6 +27,9 @@
<ClCompile Include="src\Parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PrintHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Query.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -62,6 +65,12 @@
<ClInclude Include="include\Poco\JSON\Parser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\ParseHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\PrintHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\Query.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -365,7 +365,7 @@
<File
RelativePath=".\src\Array.cpp"/>
<File
RelativePath=".\src\DefaultHandler.cpp"/>
RelativePath=".\src\ParseHandler.cpp"/>
<File
RelativePath=".\src\Handler.cpp"/>
<File
@ -374,6 +374,8 @@
RelativePath=".\src\Object.cpp"/>
<File
RelativePath=".\src\Parser.cpp"/>
<File
RelativePath=".\src\PrintHandler.cpp"/>
<File
RelativePath=".\src\Query.cpp"/>
<File
@ -399,6 +401,10 @@
RelativePath=".\include\Poco\JSON\Object.h"/>
<File
RelativePath=".\include\Poco\JSON\Parser.h"/>
<File
RelativePath=".\include\Poco\JSON\ParseHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\PrintHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\Query.h"/>
<File

View File

@ -386,7 +386,7 @@
<File
RelativePath=".\src\Array.cpp"/>
<File
RelativePath=".\src\DefaultHandler.cpp"/>
RelativePath=".\src\ParseHandler.cpp"/>
<File
RelativePath=".\src\Handler.cpp"/>
<File
@ -395,6 +395,8 @@
RelativePath=".\src\Object.cpp"/>
<File
RelativePath=".\src\Parser.cpp"/>
<File
RelativePath=".\src\PrintHandler.cpp"/>
<File
RelativePath=".\src\Query.cpp"/>
<File
@ -420,6 +422,10 @@
RelativePath=".\include\Poco\JSON\Object.h"/>
<File
RelativePath=".\include\Poco\JSON\Parser.h"/>
<File
RelativePath=".\include\Poco\JSON\ParseHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\PrintHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\Query.h"/>
<File

View File

@ -385,7 +385,7 @@
<File
RelativePath=".\src\Array.cpp"/>
<File
RelativePath=".\src\DefaultHandler.cpp"/>
RelativePath=".\src\ParseHandler.cpp"/>
<File
RelativePath=".\src\Handler.cpp"/>
<File
@ -394,6 +394,8 @@
RelativePath=".\src\Object.cpp"/>
<File
RelativePath=".\src\Parser.cpp"/>
<File
RelativePath=".\src\PrintHandler.cpp"/>
<File
RelativePath=".\src\Query.cpp"/>
<File
@ -419,6 +421,10 @@
RelativePath=".\include\Poco\JSON\Object.h"/>
<File
RelativePath=".\include\Poco\JSON\Parser.h"/>
<File
RelativePath=".\include\Poco\JSON\ParseHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\PrintHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\Query.h"/>
<File

View File

@ -272,11 +272,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\Array.cpp"/>
<ClCompile Include="src\DefaultHandler.cpp"/>
<ClCompile Include="src\ParseHandler.cpp"/>
<ClCompile Include="src\Handler.cpp"/>
<ClCompile Include="src\JSONException.cpp"/>
<ClCompile Include="src\Object.cpp"/>
<ClCompile Include="src\Parser.cpp"/>
<ClCompile Include="src\PrintHandler.cpp"/>
<ClCompile Include="src\Query.cpp"/>
<ClCompile Include="src\Stringifier.cpp"/>
<ClCompile Include="src\Template.cpp"/>
@ -290,6 +291,8 @@
<ClInclude Include="include\Poco\JSON\JSONException.h"/>
<ClInclude Include="include\Poco\JSON\Object.h"/>
<ClInclude Include="include\Poco\JSON\Parser.h"/>
<ClInclude Include="include\Poco\JSON\ParseHandler.h"/>
<ClInclude Include="include\Poco\JSON\PrintHandler.h"/>
<ClInclude Include="include\Poco\JSON\Query.h"/>
<ClInclude Include="include\Poco\JSON\Stringifier.h"/>
<ClInclude Include="include\Poco\JSON\Template.h"/>

View File

@ -12,7 +12,7 @@
<ClCompile Include="src\Array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\DefaultHandler.cpp">
<ClCompile Include="src\ParseHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Handler.cpp">
@ -27,6 +27,9 @@
<ClCompile Include="src\Parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PrintHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Query.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -62,6 +65,12 @@
<ClInclude Include="include\Poco\JSON\Parser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\ParseHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\PrintHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\Query.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -272,11 +272,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\Array.cpp"/>
<ClCompile Include="src\DefaultHandler.cpp"/>
<ClCompile Include="src\ParseHandler.cpp"/>
<ClCompile Include="src\Handler.cpp"/>
<ClCompile Include="src\JSONException.cpp"/>
<ClCompile Include="src\Object.cpp"/>
<ClCompile Include="src\Parser.cpp"/>
<ClCompile Include="src\PrintHandler.cpp"/>
<ClCompile Include="src\Query.cpp"/>
<ClCompile Include="src\Stringifier.cpp"/>
<ClCompile Include="src\Template.cpp"/>
@ -290,6 +291,8 @@
<ClInclude Include="include\Poco\JSON\JSONException.h"/>
<ClInclude Include="include\Poco\JSON\Object.h"/>
<ClInclude Include="include\Poco\JSON\Parser.h"/>
<ClInclude Include="include\Poco\JSON\ParseHandler.h"/>
<ClInclude Include="include\Poco\JSON\PrintHandler.h"/>
<ClInclude Include="include\Poco\JSON\Query.h"/>
<ClInclude Include="include\Poco\JSON\Stringifier.h"/>
<ClInclude Include="include\Poco\JSON\Template.h"/>

View File

@ -12,7 +12,7 @@
<ClCompile Include="src\Array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\DefaultHandler.cpp">
<ClCompile Include="src\ParseHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Handler.cpp">
@ -27,6 +27,9 @@
<ClCompile Include="src\Parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PrintHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Query.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -62,6 +65,12 @@
<ClInclude Include="include\Poco\JSON\Parser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\ParseHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\PrintHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\JSON\Query.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -390,7 +390,7 @@
<File
RelativePath=".\src\Array.cpp"/>
<File
RelativePath=".\src\DefaultHandler.cpp"/>
RelativePath=".\src\ParseHandler.cpp"/>
<File
RelativePath=".\src\Handler.cpp"/>
<File
@ -399,6 +399,8 @@
RelativePath=".\src\Object.cpp"/>
<File
RelativePath=".\src\Parser.cpp"/>
<File
RelativePath=".\src\PrintHandler.cpp"/>
<File
RelativePath=".\src\Query.cpp"/>
<File
@ -424,6 +426,10 @@
RelativePath=".\include\Poco\JSON\Object.h"/>
<File
RelativePath=".\include\Poco\JSON\Parser.h"/>
<File
RelativePath=".\include\Poco\JSON\ParseHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\PrintHandler.h"/>
<File
RelativePath=".\include\Poco\JSON\Query.h"/>
<File

View File

@ -11,7 +11,7 @@ include $(POCO_BASE)/build/rules/global
INCLUDE += -I $(POCO_BASE)/JSON/include/Poco/JSON
objects = Array Object Parser Handler \
Stringifier DefaultHandler Query JSONException \
Stringifier ParseHandler Query JSONException \
Template TemplateCache
target = PocoJSON

View File

@ -137,9 +137,9 @@ public:
void add(const Dynamic::Var& value);
/// Add the given value to the array
void stringify(std::ostream& out, unsigned int indent) const;
/// Prints the array to out. When indent is 0, the array
/// will be printed on one line without indentation.
void stringify(std::ostream& out, unsigned int indent = 0, int step = -1) const;
/// Prints the array to out. When indent has zero value,
/// the array will be printed without newline breaks and spaces between elements.
void remove(unsigned int index);
/// Removes the element on the given index.

View File

@ -40,137 +40,15 @@
#define JSON_DefaultHandler_INCLUDED
#include "Poco/JSON/Handler.h"
#include <stack>
#include "Poco/JSON/ParseHandler.h"
namespace Poco {
namespace JSON {
class JSON_API DefaultHandler : public Handler
/// Provides a default handler for the JSON parser.
/// This handler will build up an object or array based
/// on the handlers called by the parser.
{
public:
DefaultHandler();
/// Default Constructor
virtual ~DefaultHandler();
/// Destructor
void startObject();
/// Handles a {, meaning a new object will be read
void endObject();
/// Handles a }, meaning the object is read
void startArray();
/// Handles a [, meaning a new array will be read
void endArray();
/// Handles a ], meaning the array is read
void key(const std::string& k);
/// A key is read
Dynamic::Var result() const;
/// Returns the result of the parser. Which is an object or an array.
virtual void value(int v);
/// An integer value is read
virtual void value(unsigned v);
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
virtual void value(Int64 v);
/// A 64-bit integer value is read
virtual void value(UInt64 v);
/// An unsigned 64-bit integer value is read. This will only be
/// triggered if the value cannot fit into a signed 64-bit integer.
#endif
virtual void value(const std::string& s);
/// A string value is read.
virtual void value(double d);
/// A double value is read
virtual void value(bool b);
/// A boolean value is read
virtual void null();
/// A null value is read
private:
void setValue(const Poco::Dynamic::Var& value);
std::stack<Dynamic::Var> _stack;
std::string _key;
Dynamic::Var _result;
};
inline Dynamic::Var DefaultHandler::result() const
{
return _result;
}
inline void DefaultHandler::value(int v)
{
setValue(v);
}
inline void DefaultHandler::value(unsigned v)
{
setValue(v);
}
#if defined(POCO_HAVE_INT64)
inline void DefaultHandler::value(Int64 v)
{
setValue(v);
}
inline void DefaultHandler::value(UInt64 v)
{
setValue(v);
}
#endif
inline void DefaultHandler::value(const std::string& s)
{
setValue(s);
}
inline void DefaultHandler::value(double d)
{
setValue(d);
}
inline void DefaultHandler::value(bool b)
{
setValue(b);
}
inline void DefaultHandler::null()
{
Poco::Dynamic::Var empty;
setValue(empty);
}
//@deprecated
typedef ParseHandler DefaultHandler;
}} // namespace Poco::JSON

View File

@ -51,6 +51,9 @@ namespace JSON {
class JSON_API Handler
{
public:
Handler();
/// Constructor;
virtual void startObject() = 0;
/// The parser has read a {, meaning a new object will be read
@ -74,7 +77,7 @@ public:
virtual void value(unsigned v) = 0;
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
virtual void value(Int64 v) = 0;
@ -82,7 +85,7 @@ public:
virtual void value(UInt64 v) = 0;
/// An unsigned 64-bit integer value is read. This will only be
/// triggered if the value cannot fit into a signed 64-bit integer.
/// triggered if the value cannot fit into a signed 64-bit integer.
#endif
virtual void value(const std::string& value) = 0;
@ -94,6 +97,9 @@ public:
virtual void value(bool b) = 0;
/// A boolean value is read
virtual void comma();
/// A comma is read
protected:
virtual ~Handler();

View File

@ -46,6 +46,7 @@
#include "Poco/Dynamic/Var.h"
#include <map>
#include <vector>
#include <deque>
#include <iostream>
#include <sstream>
@ -60,8 +61,10 @@ class JSON_API Object
public:
typedef SharedPtr<Object> Ptr;
Object();
/// Default constructor
Object(bool preserveInsertionOrder = false);
/// Default constructor. If preserveInsertionOrder, object
/// will preserve the items insertion order. Otherwise, items
/// will be sorted by keys.
Object(const Object& copy);
/// Copy constructor
@ -138,17 +141,55 @@ public:
void set(const std::string& key, const Dynamic::Var& value);
/// Sets a new value
void stringify(std::ostream& out, unsigned int indent = 0) const;
void stringify(std::ostream& out, unsigned int indent = 0, int step = -1) const;
/// Prints the object to out. When indent is 0, the object
/// will be printed on one line without indentation.
/// will be printed on a single line without indentation.
void remove(const std::string& key);
/// Removes the property with the given key
private:
//TODO: unordered map
template <typename C>
void doStringify(const C& container, std::ostream& out, unsigned int indent, int step) const
{
out << '{';
if (indent > 0) out << std::endl;
for (C::const_iterator it = container.begin(); it != container.end();)
{
for(int i = 0; i < indent; i++) out << ' ';
out << '"' << getKey(it) << '"';
out << ((indent > 0) ? " : " : ":");
Stringifier::stringify(getValue(it), out, indent + step, step);
if ( ++it != container.end() ) out << ',';
if (step > 0) out << '\n';
}
if (indent >= step) indent -= step;
for (int i = 0; i < indent; i++)
out << ' ';
out << '}';
}
typedef std::map<std::string, Dynamic::Var> ValueMap;
ValueMap _values;
typedef std::deque<Dynamic::Var*> KeyPtrList;
const std::string& getKey(ValueMap::const_iterator& it) const;
const Dynamic::Var& getValue(ValueMap::const_iterator& it) const;
const std::string& getKey(KeyPtrList::const_iterator& it) const;
const Dynamic::Var& getValue(KeyPtrList::const_iterator& it) const;
ValueMap _values;
KeyPtrList _keys;
bool _preserveInsOrder;
};
@ -180,12 +221,6 @@ inline bool Object::isObject(const std::string& key) const
}
inline void Object::set(const std::string& key, const Dynamic::Var& value)
{
_values[key] = value;
}
inline std::size_t Object::size() const
{
return static_cast<std::size_t>(_values.size());
@ -198,6 +233,24 @@ inline void Object::remove(const std::string& key)
}
inline const std::string& Object::getKey(ValueMap::const_iterator& it) const
{
return it->first;
}
inline const Dynamic::Var& Object::getValue(ValueMap::const_iterator& it) const
{
return it->second;
}
inline const Dynamic::Var& Object::getValue(KeyPtrList::const_iterator& it) const
{
return **it;
}
}} // Namespace Poco::JSON

View File

@ -0,0 +1,181 @@
//
// ParseHandler.h
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: ParseHandler
//
// Definition of the ParseHandler class.
//
// 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.
//
#ifndef JSON_ParseHandler_INCLUDED
#define JSON_ParseHandler_INCLUDED
#include "Poco/JSON/Handler.h"
#include <stack>
namespace Poco {
namespace JSON {
class JSON_API ParseHandler : public Handler
/// Provides a default handler for the JSON parser.
/// This handler will build up an object or array based
/// on the handlers called by the parser.
{
public:
ParseHandler(bool preserveObjectOrder = false);
/// Creates the ParseHandler.
virtual ~ParseHandler();
/// Destroys the ParseHandler.
void startObject();
/// Handles a '{'; a new object is started.
void endObject();
/// Handles a '}'; the object is closed.
void startArray();
/// Handles a '['; a new array is started.
void endArray();
/// Handles a ']'; the array is closed.
void key(const std::string& k);
/// A key is read
Dynamic::Var result() const;
/// Returns the result of the parser (an object or an array).
virtual void value(int v);
/// An integer value is read
virtual void value(unsigned v);
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
virtual void value(Int64 v);
/// A 64-bit integer value is read
virtual void value(UInt64 v);
/// An unsigned 64-bit integer value is read. This will only be
/// triggered if the value cannot fit into a signed 64-bit integer.
#endif
virtual void value(const std::string& s);
/// A string value is read.
virtual void value(double d);
/// A double value is read.
virtual void value(bool b);
/// A boolean value is read.
virtual void null();
/// A null value is read.
private:
void setValue(const Poco::Dynamic::Var& value);
typedef std::stack<Dynamic::Var> Stack;
Stack _stack;
std::string _key;
Dynamic::Var _result;
bool _preserveObjectOrder;
};
inline Dynamic::Var ParseHandler::result() const
{
return _result;
}
inline void ParseHandler::value(int v)
{
setValue(v);
}
inline void ParseHandler::value(unsigned v)
{
setValue(v);
}
#if defined(POCO_HAVE_INT64)
inline void ParseHandler::value(Int64 v)
{
setValue(v);
}
inline void ParseHandler::value(UInt64 v)
{
setValue(v);
}
#endif
inline void ParseHandler::value(const std::string& s)
{
setValue(s);
}
inline void ParseHandler::value(double d)
{
setValue(d);
}
inline void ParseHandler::value(bool b)
{
setValue(b);
}
inline void ParseHandler::null()
{
Poco::Dynamic::Var empty;
setValue(empty);
}
}} // namespace Poco::JSON
#endif // JSON_ParseHandler_INCLUDED

View File

@ -0,0 +1,139 @@
//
// PrintHandler.h
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: PrintHandler
//
// Definition of the PrintHandler class.
//
// 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.
//
#ifndef JSON_PrintHandler_INCLUDED
#define JSON_PrintHandler_INCLUDED
#include "Poco/JSON/JSON.h"
#include "Poco/JSON/Handler.h"
namespace Poco {
namespace JSON {
class JSON_API PrintHandler : public Handler
/// PrintHandler formats and prints the JSON object
/// to either user-provided std::ostream or standard out.
/// If indent i zero, the output is condensed JSON string,
/// otherwise, the proper indentation is applied to elements.
{
public:
static const unsigned JSON_PRINT_FLAT = 0;
PrintHandler(unsigned indent = 0);
/// Creates the PrintHandler.
PrintHandler(std::ostream& out, unsigned indent = 0);
/// Creates the PrintHandler.
~PrintHandler();
/// Destroys the PrintHandler.
void startObject();
/// The parser has read a '{'; a new object is started.
/// If indent is greater than zero, a newline will be apended.
void endObject();
/// The parser has read a '}'; the object is closed.
void startArray();
/// The parser has read a [; a new array will be started.
/// If indent is greater than zero, a newline will be apended.
void endArray();
/// The parser has read a ]; the array is closed.
void key(const std::string& k);
/// A key of an object is read; it will be written to the output,
/// followed by a ':'. If indent is greater than zero, the colon
/// is padded by a space before and after.
void null();
/// A null value is read; "null" will be written to the output.
void value(int v);
/// An integer value is read.
void value(unsigned v);
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
void value(Int64 v);
/// A 64-bit integer value is read; it will be written to the output.
void value(UInt64 v);
/// An unsigned 64-bit integer value is read; it will be written to the output.
#endif
void value(const std::string& value);
/// A string value is read; it will be fromatted and written to the output.
void value(double d);
/// A double value is read; it will be written to the output.
void value(bool b);
/// A boolean value is read; it will be written to the output.
void comma();
/// A comma is read; it will be written to the output as "true" or "false".
void setIndent(unsigned indent)
{
_indent = indent;
}
private:
const char* endLine() const;
unsigned indent();
bool printFlat() const;
std::ostream& _out;
unsigned _indent;
std::string _tab;
bool _array;
};
}} // namespace Poco::JSON
#endif // JSON_PrintHandler_INCLUDED

View File

@ -53,12 +53,39 @@ class JSON_API Stringifier
/// Helper class for creating a String from a JSON object or array
{
public:
static void stringify(const Dynamic::Var& any, std::ostream& out, unsigned int indent = 0);
static void condense(const Dynamic::Var& any, std::ostream& out);
/// Writes a condensed string representation of the value to the output stream while preserving the insertion order.
/// This is just a "shortcut" to stringify(any, out) with name indicating the function effect.
static void stringify(const Dynamic::Var& any, bool preserveInsertionOrder, std::ostream& out, unsigned int indent = 0);
/// Writes a String representation of the value to the output stream while preserving the insertion order.
/// When indent is 0, the generated string will be created as small as possible (condensed).
/// When preserveInsertionOrder is true, the original string object members order will be preserved.
/// This is a "shortcut" to stringify(any, out, indent, -1, preserveInsertionOrder).
static void stringify(const Dynamic::Var& any, std::ostream& out, unsigned int indent = 0, int step = -1, bool preserveInsertionOrder = false);
/// Writes a String representation of the value to the output stream.
/// When indent is 0, the String will be created as small as possible.
/// When preserveInsertionOrder is true, the original string object members order will be preserved;
/// otherwise, object members are sorted by their names.
static void formatString(const std::string& value, std::ostream& out);
/// Formats the JSON string and streams it into ostream.
};
inline void Stringifier::condense(const Dynamic::Var& any, std::ostream& out)
{
stringify(any, out, 0, -1, true);
}
inline void Stringifier::stringify(const Dynamic::Var& any, bool preserveInsertionOrder, std::ostream& out, unsigned int indent)
{
stringify(any, out, indent, -1, preserveInsertionOrder);
}
}} // namespace Poco::JSON

View File

@ -34,7 +34,7 @@
#include "Poco/Timestamp.h"
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/DefaultHandler.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/Environment.h"
#include "Poco/Path.h"
@ -82,7 +82,7 @@ int main(int argc, char** argv)
try
{
Poco::JSON::DefaultHandler handler;
Poco::JSON::ParseHandler handler;
Poco::JSON::Parser parser;
parser.setHandler(&handler);
Poco::Timestamp time1;

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

View File

@ -39,7 +39,8 @@
#include "Poco/JSON/Query.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/JSON/Stringifier.h"
#include "Poco/JSON/DefaultHandler.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/PrintHandler.h"
#include "Poco/JSON/Template.h"
#include "Poco/Path.h"
@ -87,7 +88,7 @@ void JSONTest::testNullProperty()
Var result;
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -114,7 +115,7 @@ void JSONTest::testTrueProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -143,7 +144,7 @@ void JSONTest::testFalseProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -172,7 +173,7 @@ void JSONTest::testNumberProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -202,7 +203,7 @@ void JSONTest::testUnsignedNumberProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -233,7 +234,7 @@ void JSONTest::testNumber64Property()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -263,7 +264,7 @@ void JSONTest::testUnsignedNumber64Property()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -294,7 +295,7 @@ void JSONTest::testStringProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -323,7 +324,7 @@ void JSONTest::testEmptyObject()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -349,7 +350,7 @@ void JSONTest::testDoubleProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -378,7 +379,7 @@ void JSONTest::testDouble2Property()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -407,7 +408,7 @@ void JSONTest::testDouble3Property()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -436,7 +437,7 @@ void JSONTest::testObjectProperty()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -472,7 +473,7 @@ void JSONTest::testObjectArray()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -494,6 +495,37 @@ void JSONTest::testObjectArray()
}
void JSONTest::testArrayOfObjects()
{
std::string json = "[ {\"test\" : 0}, { \"test1\" : [1, 2, 3], \"test2\" : 4 } ]";
Parser parser;
Var result;
try
{
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
}
catch(JSONException& jsone)
{
std::cout << jsone.message() << std::endl;
assert(false);
}
assert(result.type() == typeid(Array::Ptr));
Array::Ptr arr = result.extract<Array::Ptr>();
Object::Ptr object = arr->getObject(0);
assert (object->getValue<int>("test") == 0);
object = arr->getObject(1);
arr = object->getArray("test1");
result = arr->get(0);
assert (result == 1);
}
void JSONTest::testEmptyArray()
{
std::string json = "[]";
@ -502,7 +534,7 @@ void JSONTest::testEmptyArray()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -528,7 +560,7 @@ void JSONTest::testNestedArray()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -554,7 +586,7 @@ void JSONTest::testNullElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -582,7 +614,7 @@ void JSONTest::testTrueElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -611,7 +643,7 @@ void JSONTest::testFalseElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -640,7 +672,7 @@ void JSONTest::testNumberElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -669,7 +701,7 @@ void JSONTest::testStringElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -698,7 +730,7 @@ void JSONTest::testEmptyObjectElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -725,7 +757,7 @@ void JSONTest::testDoubleElement()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -754,7 +786,7 @@ void JSONTest::testOptValue()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -781,7 +813,7 @@ void JSONTest::testQuery()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -801,15 +833,77 @@ void JSONTest::testQuery()
}
void JSONTest::testPrintHandler()
{
std::string json = "{ \"name\" : \"Homer\", \"age\" : 38, \"wife\" : \"Marge\", \"age\" : 36, \"children\" : [ \"Bart\", \"Lisa\", \"Maggie\" ] }";
Parser parser;
std::ostringstream ostr;
PrintHandler handler(ostr);
parser.setHandler(&handler);
parser.parse(json);
assert (ostr.str() == "{\"name\":\"Homer\",\"age\":38,\"wife\":\"Marge\",\"age\":36,\"children\":[\"Bart\",\"Lisa\",\"Maggie\"]}");
handler.setIndent(1);
ostr.str("");
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38,\n"
" \"wife\" : \"Marge\",\n"
" \"age\" : 36,\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ]\n"
"}"
);
handler.setIndent(2);
ostr.str("");
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38,\n"
" \"wife\" : \"Marge\",\n"
" \"age\" : 36,\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ]\n"
"}"
);
handler.setIndent(4);
ostr.str("");
parser.parse(json);
assert (ostr.str() == "{\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38,\n"
" \"wife\" : \"Marge\",\n"
" \"age\" : 36,\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ]\n"
"}"
);
}
void JSONTest::testStringify()
{
std::string json = "{ \"name\" : \"Franky\", \"children\" : [ \"Jonas\", \"Ellen\" ] }";
std::string json = "{ \"Simpsons\" : { \"husband\" : { \"name\" : \"Homer\" , \"age\" : 38 }, \"wife\" : { \"name\" : \"Marge\", \"age\" : 36 }, "
"\"children\" : [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"address\" : { \"number\" : 742, \"street\" : \"Evergreen Terrace\", \"town\" : \"Springfield\" } } }";
Parser parser;
Var result;
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -822,9 +916,221 @@ void JSONTest::testStringify()
assert(result.type() == typeid(Object::Ptr));
std::ostringstream ostr;
Stringifier::condense(result, ostr);
std::string str = "{"
"\"Simpsons\":{"
"\"address\":{"
"\"number\":742,"
"\"street\":\"Evergreen Terrace\","
"\"town\":\"Springfield\""
"},"
"\"children\":["
"\"Bart\","
"\"Lisa\","
"\"Maggie\"],"
"\"husband\":{"
"\"age\":38,"
"\"name\":\"Homer\""
"},"
"\"wife\":{"
"\"age\":36,\"name\":\"Marge\""
"}}}";
assert (ostr.str() == str);
ostr.str("");
Stringifier::stringify(result, ostr);
//TODO: need map that does not order for internal container
assert (ostr.str() == "{\"name\":\"Franky\",\"children\":[\"Jonas\",\"Ellen\"]}");
assert (ostr.str() == str);
ostr.str("");
Stringifier::stringify(result, ostr, 1);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" }\n"
" }\n"
"}";
assert (ostr.str() == str);
ostr.str("");
Stringifier::stringify(result, ostr, 2);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" }\n"
" }\n"
"}";
assert (ostr.str() == str);
ostr.str("");
Stringifier::stringify(result, ostr, 4);
str = "{\n"
" \"Simpsons\" : {\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"husband\" : {\n"
" \"age\" : 38,\n"
" \"name\" : \"Homer\"\n"
" },\n"
" \"wife\" : {\n"
" \"age\" : 36,\n"
" \"name\" : \"Marge\"\n"
" }\n"
" }\n"
"}";
assert (ostr.str() == str);
}
void JSONTest::testStringifyPreserveOrder()
{
std::string json = "{ \"Simpsons\" : { \"husband\" : { \"name\" : \"Homer\" , \"age\" : 38 }, \"wife\" : { \"name\" : \"Marge\", \"age\" : 36 }, "
"\"children\" : [ \"Bart\", \"Lisa\", \"Maggie\" ], "
"\"address\" : { \"number\" : 742, \"street\" : \"Evergreen Terrace\", \"town\" : \"Springfield\" } } }";
Parser parser;
Var result;
try
{
ParseHandler handler(true);
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
}
catch(JSONException& jsone)
{
std::cout << jsone.message() << std::endl;
assert(false);
}
assert(result.type() == typeid(Object::Ptr));
std::ostringstream ostr;
Stringifier::condense(result, ostr);
assert (ostr.str() == "{\"Simpsons\":{\"husband\":{\"name\":\"Homer\",\"age\":38},\"wife\":{\"name\":\"Marge\",\"age\":36},"
"\"children\":[\"Bart\",\"Lisa\",\"Maggie\"],"
"\"address\":{\"number\":742,\"street\":\"Evergreen Terrace\",\"town\":\"Springfield\"}}}");
ostr.str("");
Stringifier::stringify(result, ostr);
assert (ostr.str() == "{\"Simpsons\":{\"husband\":{\"name\":\"Homer\",\"age\":38},\"wife\":{\"name\":\"Marge\",\"age\":36},"
"\"children\":[\"Bart\",\"Lisa\",\"Maggie\"],"
"\"address\":{\"number\":742,\"street\":\"Evergreen Terrace\",\"town\":\"Springfield\"}}}");
ostr.str("");
Stringifier::stringify(result, ostr, 1);
assert (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" }\n"
" }\n"
"}");
ostr.str("");
Stringifier::stringify(result, ostr, 2);
assert (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" }\n"
" }\n"
"}");
ostr.str("");
Stringifier::stringify(result, ostr, 4);
assert (ostr.str() == "{\n"
" \"Simpsons\" : {\n"
" \"husband\" : {\n"
" \"name\" : \"Homer\",\n"
" \"age\" : 38\n"
" },\n"
" \"wife\" : {\n"
" \"name\" : \"Marge\",\n"
" \"age\" : 36\n"
" },\n"
" \"children\" : [\n"
" \"Bart\",\n"
" \"Lisa\",\n"
" \"Maggie\"\n"
" ],\n"
" \"address\" : {\n"
" \"number\" : 742,\n"
" \"street\" : \"Evergreen Terrace\",\n"
" \"town\" : \"Springfield\"\n"
" }\n"
" }\n"
"}");
}
@ -852,7 +1158,7 @@ void JSONTest::testValidJanssonFiles()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(fis);
result = handler.result();
@ -900,7 +1206,7 @@ void JSONTest::testInvalidJanssonFiles()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(fis);
result = handler.result();
@ -944,7 +1250,7 @@ void JSONTest::testInvalidUnicodeJanssonFiles()
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(fis);
result = handler.result();
@ -977,6 +1283,7 @@ void JSONTest::testTemplate()
tpl.render(data, std::cout);
}
void JSONTest::testUnicode()
{
const unsigned char supp[] = {0x61, 0xE1, 0xE9, 0x78, 0xED, 0xF3, 0xFA, 0x0};
@ -988,7 +1295,7 @@ void JSONTest::testUnicode()
Var result;
try
{
DefaultHandler handler;
ParseHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
@ -1012,6 +1319,7 @@ void JSONTest::testUnicode()
assert(test.convert<std::string>() == original);
}
std::string JSONTest::getTestFilesPath(const std::string& type)
{
std::ostringstream ostr;
@ -1060,6 +1368,7 @@ CppUnit::Test* JSONTest::suite()
CppUnit_addTest(pSuite, JSONTest, testDouble3Property);
CppUnit_addTest(pSuite, JSONTest, testObjectProperty);
CppUnit_addTest(pSuite, JSONTest, testObjectArray);
CppUnit_addTest(pSuite, JSONTest, testArrayOfObjects);
CppUnit_addTest(pSuite, JSONTest, testEmptyArray);
CppUnit_addTest(pSuite, JSONTest, testNestedArray);
CppUnit_addTest(pSuite, JSONTest, testNullElement);
@ -1071,7 +1380,9 @@ CppUnit::Test* JSONTest::suite()
CppUnit_addTest(pSuite, JSONTest, testDoubleElement);
CppUnit_addTest(pSuite, JSONTest, testOptValue);
CppUnit_addTest(pSuite, JSONTest, testQuery);
CppUnit_addTest(pSuite, JSONTest, testPrintHandler);
CppUnit_addTest(pSuite, JSONTest, testStringify);
CppUnit_addTest(pSuite, JSONTest, testStringifyPreserveOrder);
CppUnit_addTest(pSuite, JSONTest, testValidJanssonFiles);
CppUnit_addTest(pSuite, JSONTest, testInvalidJanssonFiles);
CppUnit_addTest(pSuite, JSONTest, testInvalidUnicodeJanssonFiles);

View File

@ -62,6 +62,7 @@ public:
void testDouble3Property();
void testObjectProperty();
void testObjectArray();
void testArrayOfObjects();
void testEmptyArray();
void testNestedArray();
void testNullElement();
@ -73,7 +74,9 @@ public:
void testDoubleElement();
void testOptValue();
void testQuery();
void testPrintHandler();
void testStringify();
void testStringifyPreserveOrder();
void testValidJanssonFiles();
void testInvalidJanssonFiles();