added a flatten function

This commit is contained in:
Niels 2016-04-16 16:39:20 +02:00
parent 3401954f5b
commit 007359675b
3 changed files with 217 additions and 52 deletions

View file

@ -8907,32 +8907,6 @@ basic_json_parser_63:
/// the reference tokens /// the reference tokens
std::vector<std::string> reference_tokens {}; std::vector<std::string> reference_tokens {};
/*!
@brief replace all occurrences of a substring by another string
@param[in,out] s the string to manipulate
@param[in] f the substring to replace with @a t
@param[out] t the string to replace @a f
@return The string @a s where all occurrences of @a f are replaced
with @a t.
@pre The search string @a f must not be empty.
*/
static void replace_substring(std::string& s,
const std::string& f,
const std::string& t)
{
assert(not f.empty());
for (
size_t pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t
pos = s.find(f, pos + t.size()) // find next occurrence of f
);
}
/// split the string input to reference tokens /// split the string input to reference tokens
void split(std::string reference_string) void split(std::string reference_string)
{ {
@ -8993,7 +8967,92 @@ basic_json_parser_63:
reference_tokens.push_back(reference_token); reference_tokens.push_back(reference_token);
} }
} }
/*!
@brief replace all occurrences of a substring by another string
@param[in,out] s the string to manipulate
@param[in] f the substring to replace with @a t
@param[out] t the string to replace @a f
@return The string @a s where all occurrences of @a f are replaced
with @a t.
@pre The search string @a f must not be empty.
@since version 2.0.0
*/
static void replace_substring(std::string& s,
const std::string& f,
const std::string& t)
{
assert(not f.empty());
for (
size_t pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t
pos = s.find(f, pos + t.size()) // find next occurrence of f
);
}
/*!
@param[in] reference_string the reference string to the current value
@param[in] value the value to consider
@param[in,out] result the result object to insert values to
*/
static void flatten(const std::string reference_string,
const basic_json& value,
basic_json& result)
{
switch (value.m_type)
{
case value_t::array:
{
// iterate array and use index as reference string
for (size_t i = 0; i < value.m_value.array->size(); ++i)
{
flatten(reference_string + "/" + std::to_string(i),
value.m_value.array->operator[](i), result);
}
break;
}
case value_t::object:
{
// iterate object and use keys as reference string
for (const auto& element : *value.m_value.object)
{
// escape "~"" to "~0" and "/" to "~1"
std::string key(element.first);
replace_substring(key, "~", "~0");
replace_substring(key, "/", "~1");
flatten(reference_string + "/" + key,
element.second, result);
}
break;
}
default:
{
// add primitive value with its reference string
result[reference_string] = value;
break;
}
}
}
}; };
/*!
@return an object that maps JSON pointers to primitve values
*/
basic_json flatten() const
{
basic_json result(value_t::object);
json_pointer::flatten("", *this, result);
return result;
}
}; };

View file

@ -8217,32 +8217,6 @@ class basic_json
/// the reference tokens /// the reference tokens
std::vector<std::string> reference_tokens {}; std::vector<std::string> reference_tokens {};
/*!
@brief replace all occurrences of a substring by another string
@param[in,out] s the string to manipulate
@param[in] f the substring to replace with @a t
@param[out] t the string to replace @a f
@return The string @a s where all occurrences of @a f are replaced
with @a t.
@pre The search string @a f must not be empty.
*/
static void replace_substring(std::string& s,
const std::string& f,
const std::string& t)
{
assert(not f.empty());
for (
size_t pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t
pos = s.find(f, pos + t.size()) // find next occurrence of f
);
}
/// split the string input to reference tokens /// split the string input to reference tokens
void split(std::string reference_string) void split(std::string reference_string)
{ {
@ -8303,7 +8277,92 @@ class basic_json
reference_tokens.push_back(reference_token); reference_tokens.push_back(reference_token);
} }
} }
/*!
@brief replace all occurrences of a substring by another string
@param[in,out] s the string to manipulate
@param[in] f the substring to replace with @a t
@param[out] t the string to replace @a f
@return The string @a s where all occurrences of @a f are replaced
with @a t.
@pre The search string @a f must not be empty.
@since version 2.0.0
*/
static void replace_substring(std::string& s,
const std::string& f,
const std::string& t)
{
assert(not f.empty());
for (
size_t pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t
pos = s.find(f, pos + t.size()) // find next occurrence of f
);
}
/*!
@param[in] reference_string the reference string to the current value
@param[in] value the value to consider
@param[in,out] result the result object to insert values to
*/
static void flatten(const std::string reference_string,
const basic_json& value,
basic_json& result)
{
switch (value.m_type)
{
case value_t::array:
{
// iterate array and use index as reference string
for (size_t i = 0; i < value.m_value.array->size(); ++i)
{
flatten(reference_string + "/" + std::to_string(i),
value.m_value.array->operator[](i), result);
}
break;
}
case value_t::object:
{
// iterate object and use keys as reference string
for (const auto& element : *value.m_value.object)
{
// escape "~"" to "~0" and "/" to "~1"
std::string key(element.first);
replace_substring(key, "~", "~0");
replace_substring(key, "/", "~1");
flatten(reference_string + "/" + key,
element.second, result);
}
break;
}
default:
{
// add primitive value with its reference string
result[reference_string] = value;
break;
}
}
}
}; };
/*!
@return an object that maps JSON pointers to primitve values
*/
basic_json flatten() const
{
basic_json result(value_t::object);
json_pointer::flatten("", *this, result);
return result;
}
}; };

View file

@ -12168,6 +12168,53 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH(json::json_pointer("/~"), "escape error: '~' must be followed with '0' or '1'"); CHECK_THROWS_WITH(json::json_pointer("/~"), "escape error: '~' must be followed with '0' or '1'");
} }
} }
SECTION("flatten")
{
json j =
{
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{
"answer", {
{"everything", 42}
}
},
{"list", {1, 0, 2}},
{
"object", {
{"currency", "USD"},
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
json j_flatten =
{
{"/pi", 3.141},
{"/happy", true},
{"/name", "Niels"},
{"/nothing", nullptr},
{"/answer/everything", 42},
{"/list/0", 1},
{"/list/1", 0},
{"/list/2", 2},
{"/object/currency", "USD"},
{"/object/value", 42.99},
{"/object/", "empty string"},
{"/object/~1", "slash"},
{"/object/~0", "tilde"},
{"/object/~01", "tilde1"}
};
CHECK(j.flatten() == j_flatten);
}
} }
TEST_CASE("regression tests") TEST_CASE("regression tests")