mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 08:31:43 +02:00
fixed GH #99: JSON::Query an JSON::Object
- fixed GH #99: JSON::Query an JSON::Object - swapped order of AnyCast(const Any&) and AnyCast(Any&) definitions
This commit is contained in:
@@ -76,6 +76,7 @@ Release 1.5.2 (2013-06-xx)
|
||||
- fixed GH #185: Poco::NumberFormatter::format(double value, int precision)
|
||||
ignore precision == 0
|
||||
- fixed GH #138: FreeBSD JSON tests fail
|
||||
- fixed GH #99: JSON::Query an JSON::Object
|
||||
|
||||
|
||||
Release 1.5.1 (2013-01-11)
|
||||
|
@@ -533,23 +533,6 @@ const ValueType* AnyCast(const Any* operand)
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType AnyCast(const Any& operand)
|
||||
/// AnyCast operator used to extract a copy of the ValueType from an const Any&.
|
||||
///
|
||||
/// Example Usage:
|
||||
/// MyType tmp = AnyCast<MyType>(anAny).
|
||||
/// Will throw a BadCastException if the cast fails.
|
||||
/// Dont use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& = ...
|
||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||
/// these cases.
|
||||
{
|
||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
||||
|
||||
return AnyCast<NonRef&>(const_cast<Any&>(operand));
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType AnyCast(Any& operand)
|
||||
/// AnyCast operator used to extract a copy of the ValueType from an Any&.
|
||||
@@ -569,6 +552,23 @@ ValueType AnyCast(Any& operand)
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType AnyCast(const Any& operand)
|
||||
/// AnyCast operator used to extract a copy of the ValueType from an const Any&.
|
||||
///
|
||||
/// Example Usage:
|
||||
/// MyType tmp = AnyCast<MyType>(anAny).
|
||||
/// Will throw a BadCastException if the cast fails.
|
||||
/// Dont use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& = ...
|
||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||
/// these cases.
|
||||
{
|
||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
||||
|
||||
return AnyCast<NonRef&>(const_cast<Any&>(operand));
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
const ValueType& RefAnyCast(const Any & operand)
|
||||
/// AnyCast operator used to return a const reference to the internal data.
|
||||
|
@@ -186,6 +186,9 @@ public:
|
||||
static Poco::Dynamic::Array makeArray(const JSON::Array::Ptr& arr);
|
||||
/// Utility function for creation of array.
|
||||
|
||||
void clear();
|
||||
/// Clears the contents of the array.
|
||||
|
||||
private:
|
||||
typedef SharedPtr<Poco::Dynamic::Array> ArrayPtr;
|
||||
|
||||
@@ -389,6 +392,145 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class VarHolderImpl<JSON::Array>: public VarHolder
|
||||
{
|
||||
public:
|
||||
VarHolderImpl(const JSON::Array& val): _val(val)
|
||||
{
|
||||
}
|
||||
|
||||
~VarHolderImpl()
|
||||
{
|
||||
}
|
||||
|
||||
const std::type_info& type() const
|
||||
{
|
||||
return typeid(JSON::Array);
|
||||
}
|
||||
|
||||
void convert(Int8&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int16&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int32&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int64&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt8&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt16&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt32&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt64&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(bool& value) const
|
||||
{
|
||||
value = _val.size() > 0;
|
||||
}
|
||||
|
||||
void convert(float&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(double&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(char&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(std::string& s) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
_val.stringify(oss, 2);
|
||||
s = oss.str();
|
||||
}
|
||||
|
||||
void convert(DateTime& /*val*/) const
|
||||
{
|
||||
throw BadCastException("Cannot convert Array to DateTime");
|
||||
}
|
||||
|
||||
void convert(LocalDateTime& /*ldt*/) const
|
||||
{
|
||||
throw BadCastException("Cannot convert Array to LocalDateTime");
|
||||
}
|
||||
|
||||
void convert(Timestamp& /*ts*/) const
|
||||
{
|
||||
throw BadCastException("Cannot convert Array to Timestamp");
|
||||
}
|
||||
|
||||
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
|
||||
{
|
||||
return cloneHolder(pVarHolder, _val);
|
||||
}
|
||||
|
||||
const JSON::Array& value() const
|
||||
{
|
||||
return _val;
|
||||
}
|
||||
|
||||
bool isArray() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInteger() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isSigned() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNumeric() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isString() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
JSON::Array _val;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace Poco::JSON
|
||||
|
||||
|
||||
|
@@ -206,6 +206,10 @@ public:
|
||||
operator const Poco::DynamicStruct& () const;
|
||||
/// Cast operator to Poco::DynamiStruct.
|
||||
|
||||
void clear();
|
||||
/// Clears the contents of the object. Insertion order
|
||||
/// preservation property is left intact.
|
||||
|
||||
private:
|
||||
template <typename C>
|
||||
void doStringify(const C& container, std::ostream& out, unsigned int indent, int step) const
|
||||
@@ -472,6 +476,148 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class VarHolderImpl<JSON::Object>: public VarHolder
|
||||
{
|
||||
public:
|
||||
VarHolderImpl(const JSON::Object& val): _val(val)
|
||||
{
|
||||
}
|
||||
|
||||
~VarHolderImpl()
|
||||
{
|
||||
}
|
||||
|
||||
const std::type_info& type() const
|
||||
{
|
||||
return typeid(JSON::Object);
|
||||
}
|
||||
|
||||
void convert(Int8&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int16&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int32&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(Int64&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt8&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt16&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt32&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(UInt64&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(bool& value) const
|
||||
{
|
||||
value = _val.size() > 0;
|
||||
}
|
||||
|
||||
void convert(float&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(double&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(char&) const
|
||||
{
|
||||
throw BadCastException();
|
||||
}
|
||||
|
||||
void convert(std::string& s) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
_val.stringify(oss, 2);
|
||||
s = oss.str();
|
||||
}
|
||||
|
||||
void convert(DateTime& /*val*/) const
|
||||
{
|
||||
//TODO: val = _val;
|
||||
throw NotImplementedException("Conversion not implemented: JSON:Object => DateTime");
|
||||
}
|
||||
|
||||
void convert(LocalDateTime& /*ldt*/) const
|
||||
{
|
||||
//TODO: ldt = _val.timestamp();
|
||||
throw NotImplementedException("Conversion not implemented: JSON:Object => LocalDateTime");
|
||||
}
|
||||
|
||||
void convert(Timestamp& /*ts*/) const
|
||||
{
|
||||
//TODO: ts = _val.timestamp();
|
||||
throw NotImplementedException("Conversion not implemented: JSON:Object => Timestamp");
|
||||
}
|
||||
|
||||
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
|
||||
{
|
||||
return cloneHolder(pVarHolder, _val);
|
||||
}
|
||||
|
||||
const JSON::Object& value() const
|
||||
{
|
||||
return _val;
|
||||
}
|
||||
|
||||
bool isArray() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInteger() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isSigned() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNumeric() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isString() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
JSON::Object _val;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace Poco::JSON
|
||||
|
||||
|
||||
|
@@ -53,18 +53,38 @@ class JSON_API Query
|
||||
{
|
||||
public:
|
||||
Query(const Dynamic::Var& source);
|
||||
/// Constructor. Pass the start object/array.
|
||||
/// Constructor. Pass the start object/array or Ptr thereof.
|
||||
/// Creating Query holding Ptr will typically result in faster
|
||||
/// performance.
|
||||
|
||||
virtual ~Query();
|
||||
/// Destructor
|
||||
|
||||
Object::Ptr findObject(const std::string& path) const;
|
||||
/// Search for an object. When the object can't be found, an empty
|
||||
/// SharedPtr is returned.
|
||||
/// Search for an object. When the object can't be found, a zero Ptr
|
||||
/// is returned; otherwise, a shared pointer to internally held object
|
||||
/// is returned.
|
||||
/// If object (as opposed to a pointer to object) is held
|
||||
/// internally, a shared pointer to new (heap-allocated) Object is
|
||||
/// returned; this may be expensive operation.
|
||||
|
||||
Object& findObject(const std::string& path, Object& obj) const;
|
||||
/// Search for an object. If object is found, it is assigned to the
|
||||
/// Object through the reference passed in. When the object can't be
|
||||
/// found, the provided Object is emptied and returned.
|
||||
|
||||
Array::Ptr findArray(const std::string& path) const;
|
||||
/// Search for an array. When the array can't be found, an empty
|
||||
/// SharedPtr is returned.
|
||||
/// Search for an array. When the array can't be found, a zero Ptr
|
||||
/// is returned; otherwise, a shared pointer to internally held array
|
||||
/// is returned.
|
||||
/// If array (as opposed to a pointer to array) is held
|
||||
/// internally, a shared pointer to new (heap-allocated) Object is
|
||||
/// returned; this may be expensive operation.
|
||||
|
||||
Array& findArray(const std::string& path, Array& obj) const;
|
||||
/// Search for an array. If array is found, it is assigned to the
|
||||
/// Object through the reference passed in. When the array can't be
|
||||
/// found, the provided Object is emptied and returned.
|
||||
|
||||
Dynamic::Var find(const std::string& path) const;
|
||||
/// Searches a value
|
||||
|
@@ -222,4 +222,11 @@ Poco::Dynamic::Array Array::makeArray(const JSON::Array::Ptr& arr)
|
||||
}
|
||||
|
||||
|
||||
void Array::clear()
|
||||
{
|
||||
_values.clear();
|
||||
_pArray = 0;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::JSON
|
||||
|
@@ -206,4 +206,12 @@ Object::operator const Poco::DynamicStruct& () const
|
||||
}
|
||||
|
||||
|
||||
void Object::clear()
|
||||
{
|
||||
_values.clear();
|
||||
_keys.clear();
|
||||
_pStruct = 0;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::JSON
|
||||
|
@@ -50,7 +50,6 @@ namespace JSON {
|
||||
|
||||
Query::Query(const Var& source): _source(source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -61,24 +60,56 @@ Query::~Query()
|
||||
|
||||
Object::Ptr Query::findObject(const std::string& path) const
|
||||
{
|
||||
Object::Ptr obj;
|
||||
Var result = find(path);
|
||||
if ( result.type() == typeid(Object::Ptr) )
|
||||
{
|
||||
obj = result.extract<Object::Ptr>();
|
||||
}
|
||||
|
||||
if (result.type() == typeid(Object::Ptr))
|
||||
return result.extract<Object::Ptr>();
|
||||
else if (result.type() == typeid(Object))
|
||||
return new Object(result.extract<Object>());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Object& Query::findObject(const std::string& path, Object& obj) const
|
||||
{
|
||||
obj.clear();
|
||||
|
||||
Var result = find(path);
|
||||
|
||||
if (result.type() == typeid(Object::Ptr))
|
||||
obj = *result.extract<Object::Ptr>();
|
||||
else if (result.type() == typeid(Object))
|
||||
obj = result.extract<Object>();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
Array::Ptr Query::findArray(const std::string& path) const
|
||||
{
|
||||
Array::Ptr arr;
|
||||
Var result = find(path);
|
||||
if ( result.type() == typeid(Array::Ptr) )
|
||||
{
|
||||
arr = result.extract<Array::Ptr>();
|
||||
}
|
||||
|
||||
if (result.type() == typeid(Array::Ptr))
|
||||
return result.extract<Array::Ptr>();
|
||||
else if (result.type() == typeid(Array))
|
||||
return new Array(result.extract<Array>());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Array& Query::findArray(const std::string& path, Array& arr) const
|
||||
{
|
||||
arr.clear();
|
||||
|
||||
Var result = find(path);
|
||||
|
||||
if (result.type() == typeid(Array::Ptr))
|
||||
arr = *result.extract<Array::Ptr>();
|
||||
else if (result.type() == typeid(Array))
|
||||
arr = result.extract<Array>();
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -89,16 +120,16 @@ Var Query::find(const std::string& path) const
|
||||
StringTokenizer tokenizer(path, ".");
|
||||
for(StringTokenizer::Iterator token = tokenizer.begin(); token != tokenizer.end(); token++)
|
||||
{
|
||||
if ( !result.isEmpty() )
|
||||
if (!result.isEmpty())
|
||||
{
|
||||
std::vector<int> indexes;
|
||||
RegularExpression::MatchVec matches;
|
||||
int firstOffset = -1;
|
||||
int offset = 0;
|
||||
RegularExpression regex("\\[([0-9]+)\\]");
|
||||
while(regex.match(*token, offset, matches) > 0 )
|
||||
while(regex.match(*token, offset, matches) > 0)
|
||||
{
|
||||
if ( firstOffset == -1 )
|
||||
if (firstOffset == -1)
|
||||
{
|
||||
firstOffset = static_cast<int>(matches[0].offset);
|
||||
}
|
||||
@@ -108,33 +139,40 @@ Var Query::find(const std::string& path) const
|
||||
}
|
||||
|
||||
std::string name(*token);
|
||||
if ( firstOffset != -1 )
|
||||
if (firstOffset != -1)
|
||||
{
|
||||
name = name.substr(0, firstOffset);
|
||||
}
|
||||
|
||||
if ( name.length() > 0 )
|
||||
if (name.length() > 0)
|
||||
{
|
||||
if ( result.type() == typeid(Object::Ptr) )
|
||||
if (result.type() == typeid(Object::Ptr))
|
||||
{
|
||||
Object::Ptr o = result.extract<Object::Ptr>();
|
||||
result = o->get(name);
|
||||
}
|
||||
else if (result.type() == typeid(Object))
|
||||
{
|
||||
Object o = result.extract<Object>();
|
||||
result = o.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.isEmpty()
|
||||
&& !indexes.empty() )
|
||||
if (!result.isEmpty() && !indexes.empty())
|
||||
{
|
||||
for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end(); ++it )
|
||||
for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end(); ++it)
|
||||
{
|
||||
if ( result.type() == typeid(Array::Ptr) )
|
||||
if (result.type() == typeid(Array::Ptr))
|
||||
{
|
||||
Array::Ptr array = result.extract<Array::Ptr>();
|
||||
result = array->get(*it);
|
||||
if ( result.isEmpty() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (result.isEmpty()) break;
|
||||
}
|
||||
else if (result.type() == typeid(Array))
|
||||
{
|
||||
Array array = result.extract<Array>();
|
||||
result = array.get(*it);
|
||||
if (result.isEmpty()) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1033,7 +1033,7 @@ void JSONTest::testOptValue()
|
||||
|
||||
void JSONTest::testQuery()
|
||||
{
|
||||
std::string json = "{ \"name\" : \"Franky\", \"children\" : [ \"Jonas\", \"Ellen\" ] }";
|
||||
std::string json = "{ \"name\" : \"Franky\", \"children\" : [ \"Jonas\", \"Ellen\" ], \"address\": { \"street\": \"A Street\", \"number\": 123, \"city\":\"The City\"} }";
|
||||
Parser parser;
|
||||
Var result;
|
||||
|
||||
@@ -1059,6 +1059,43 @@ void JSONTest::testQuery()
|
||||
assert (ds["children"].size() == 2);
|
||||
assert (ds["children"][0] == "Jonas");
|
||||
assert (ds["children"][1] == "Ellen");
|
||||
|
||||
Object::Ptr pAddress = query.findObject("address");
|
||||
assert (pAddress->getValue<std::string>("street") == "A Street");
|
||||
pAddress = query.findObject("bad address");
|
||||
assert (pAddress.isNull());
|
||||
|
||||
Object address;
|
||||
address.set("dummy", 123);
|
||||
query.findObject("bad address", address);
|
||||
assert (!address.has("dummy"));
|
||||
Object& rAddress = query.findObject("address", address);
|
||||
assert (rAddress.getValue<int>("number") == 123);
|
||||
|
||||
using Poco::JSON::Array;
|
||||
|
||||
Array::Ptr pChildren = query.findArray("children");
|
||||
assert (pChildren->getElement<std::string>(0) == "Jonas");
|
||||
pChildren = query.findArray("no children");
|
||||
assert (pChildren.isNull());
|
||||
|
||||
Array children;
|
||||
children.add("dummy");
|
||||
query.findArray("no children", children);
|
||||
assert (children.size() == 0);
|
||||
Array& rChildren = query.findArray("children", children);
|
||||
assert (rChildren.getElement<std::string>(1) == "Ellen");
|
||||
|
||||
Object::Ptr pObj = new Poco::JSON::Object;
|
||||
pObj->set("Id", 22);
|
||||
|
||||
Query queryPointer(pObj);
|
||||
Var idQueryPointer = queryPointer.find("Id");
|
||||
assert(22 == idQueryPointer);
|
||||
|
||||
Query queryObj(*pObj);
|
||||
Var idQueryObj = queryObj.find("Id");
|
||||
assert (22 == idQueryObj);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user