feat(DynamicStruct): toString() escaping #3833

This commit is contained in:
Alex Fabijanic
2022-10-13 11:50:53 +02:00
parent d11e48f851
commit a2c09c29d8
5 changed files with 65 additions and 89 deletions

View File

@@ -32,6 +32,37 @@ namespace Poco {
namespace Dynamic { namespace Dynamic {
template <typename S, typename I = typename S::ConstIterator>
std::string structToString(const S& data, bool wrap = true)
/// Utility function for converting DynamicStruct to std::string.
/// Set wrap to false in order to prevent string values wrapping
/// (useful to prevent JSON fragments from being treated as strings).
{
std::string val;
val.append("{ ");
I it = data.begin();
I itEnd = data.end();
if (!data.empty())
{
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second, wrap);
++it;
}
for (; it != itEnd; ++it)
{
val.append(", ");
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second, wrap);
}
val.append(" }");
return val;
}
template <typename K, typename M = std::map<K, Var>, typename S = std::set<K>> template <typename K, typename M = std::map<K, Var>, typename S = std::set<K>>
class Struct class Struct
/// Struct allows to define a named collection of Var objects. /// Struct allows to define a named collection of Var objects.
@@ -226,11 +257,20 @@ public:
return it->second; return it->second;
} }
std::string toString() const std::string toString(bool wrap = true) const
/// Returns the DynamicStruct as string.
///
/// To prevent unwanted string wrapping
/// (eg. when a value is JSON string),
/// `wrap` should be false. Note, however,
/// that wrap argument is of a limited utility
/// because it applies to the entire Struct,
/// so it should not be relied on when mixed content
/// (ie. plain string, which should be wrapped,
/// and JSON-as-string entries, which shouldn't)
/// is held.
{ {
std::string str; return structToString<Data, ConstIterator>(_data, wrap);
Var(*this).template convert<std::string>(str);
return str;
} }
private: private:
@@ -332,26 +372,7 @@ public:
void convert(std::string& val) const void convert(std::string& val) const
{ {
val.append("{ "); val = structToString(_val);
ValueType::ConstIterator it = _val.begin();
ValueType::ConstIterator itEnd = _val.end();
if (!_val.empty())
{
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
++it;
}
for (; it != itEnd; ++it)
{
val.append(", ");
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
}
val.append(" }");
} }
void convert(Poco::DateTime&) const void convert(Poco::DateTime&) const
@@ -518,26 +539,7 @@ public:
void convert(std::string& val) const void convert(std::string& val) const
{ {
val.append("{ "); val = structToString(_val);
ValueType::ConstIterator it = _val.begin();
ValueType::ConstIterator itEnd = _val.end();
if (!_val.empty())
{
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
++it;
}
for (; it != itEnd; ++it)
{
val.append(", ");
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
}
val.append(" }");
} }
void convert(Poco::DateTime&) const void convert(Poco::DateTime&) const
@@ -704,26 +706,7 @@ public:
void convert(std::string& val) const void convert(std::string& val) const
{ {
val.append("{ "); val = structToString(_val);
ValueType::ConstIterator it = _val.begin();
ValueType::ConstIterator itEnd = _val.end();
if (!_val.empty())
{
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
++it;
}
for (; it != itEnd; ++it)
{
val.append(", ");
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
}
val.append(" }");
} }
void convert(Poco::DateTime&) const void convert(Poco::DateTime&) const
@@ -890,26 +873,7 @@ public:
void convert(std::string& val) const void convert(std::string& val) const
{ {
val.append("{ "); val = structToString(_val);
ValueType::ConstIterator it = _val.begin();
ValueType::ConstIterator itEnd = _val.end();
if (!_val.empty())
{
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
++it;
}
for (; it != itEnd; ++it)
{
val.append(", ");
Var key(it->first);
Impl::appendJSONKey(val, key);
val.append(": ");
Impl::appendJSONValue(val, it->second);
}
val.append(" }");
} }
void convert(Poco::DateTime&) const void convert(Poco::DateTime&) const

View File

@@ -67,10 +67,12 @@ void Foundation_API appendJSONString(std::string& val, const Var& any);
/// regardless of the underlying type) and appends it to val. /// regardless of the underlying type) and appends it to val.
void Foundation_API appendJSONValue(std::string& val, const Var& any); void Foundation_API appendJSONValue(std::string& val, const Var& any, bool wrap = true);
/// Converts the any to a JSON value (if underlying type qualifies /// Converts the any to a JSON value (if underlying type qualifies
/// as string - see isJSONString() - , it is wrapped into double quotes) /// as string - see isJSONString() - it is wrapped into double quotes)
/// and appends it to val /// and appends it to val.
/// Wrapping can be prevented (useful for appending JSON fragments) by setting
/// the wrap argument to false.
template <typename C> template <typename C>

View File

@@ -66,7 +66,7 @@ void appendJSONKey(std::string& val, const Var& any)
} }
void appendJSONValue(std::string& val, const Var& any) void appendJSONValue(std::string& val, const Var& any, bool wrap)
{ {
if (any.isEmpty()) if (any.isEmpty())
{ {
@@ -74,7 +74,7 @@ void appendJSONValue(std::string& val, const Var& any)
} }
else else
{ {
bool isStr = isJSONString(any); bool isStr = wrap && isJSONString(any);
if (isStr) if (isStr)
{ {
appendJSONString(val, any.convert<std::string>()); appendJSONString(val, any.convert<std::string>());

View File

@@ -2286,6 +2286,14 @@ void VarTest::testOrderedDynamicStructBasics()
} }
void VarTest::testDynamicStructNoEscapeString()
{
DynamicStruct aStruct;
aStruct["Birthday"] = "{ \"Day\": 12, \"Month\": \"May\", \"Year\": 2005 }";
assertEqual(aStruct.toString(false), "{ \"Birthday\": { \"Day\": 12, \"Month\": \"May\", \"Year\": 2005 } }");
}
void VarTest::testDynamicStructString() void VarTest::testDynamicStructString()
{ {
DynamicStruct aStruct; DynamicStruct aStruct;
@@ -3131,6 +3139,7 @@ CppUnit::Test* VarTest::suite()
CppUnit_addTest(pSuite, VarTest, testDynamicPair); CppUnit_addTest(pSuite, VarTest, testDynamicPair);
CppUnit_addTest(pSuite, VarTest, testDynamicStructBasics); CppUnit_addTest(pSuite, VarTest, testDynamicStructBasics);
CppUnit_addTest(pSuite, VarTest, testOrderedDynamicStructBasics); CppUnit_addTest(pSuite, VarTest, testOrderedDynamicStructBasics);
CppUnit_addTest(pSuite, VarTest, testDynamicStructNoEscapeString);
CppUnit_addTest(pSuite, VarTest, testDynamicStructString); CppUnit_addTest(pSuite, VarTest, testDynamicStructString);
CppUnit_addTest(pSuite, VarTest, testOrderedDynamicStructString); CppUnit_addTest(pSuite, VarTest, testOrderedDynamicStructString);
CppUnit_addTest(pSuite, VarTest, testDynamicStructInt); CppUnit_addTest(pSuite, VarTest, testDynamicStructInt);

View File

@@ -57,6 +57,7 @@ public:
void testDynamicStructBasics(); void testDynamicStructBasics();
void testOrderedDynamicStructBasics(); void testOrderedDynamicStructBasics();
void testDynamicStructString(); void testDynamicStructString();
void testDynamicStructNoEscapeString();
void testOrderedDynamicStructString(); void testOrderedDynamicStructString();
void testDynamicStructInt(); void testDynamicStructInt();
void testOrderedDynamicStructInt(); void testOrderedDynamicStructInt();