Add Pointer::Erase() and EraseValueByPointer()
This commit is contained in:
parent
a3e5fcf490
commit
8c01e7e1ce
@ -65,6 +65,12 @@ Pointer("/hello").Swap(d, x);
|
|||||||
|
|
||||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
|
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
|
||||||
// x becomes "world"
|
// x becomes "world"
|
||||||
|
|
||||||
|
// Erase a member or element, return true if the value exists
|
||||||
|
bool success = Pointer("/a").Erase(d);
|
||||||
|
assert(success);
|
||||||
|
|
||||||
|
// { "project" : "RapidJSON", "stars" : 10 }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
# Helper Functions {#HelperFunctions}
|
# Helper Functions {#HelperFunctions}
|
||||||
@ -88,6 +94,9 @@ Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
|
|||||||
|
|
||||||
Value x("C++");
|
Value x("C++");
|
||||||
SwapValueByPointer(d, "/hello", x);
|
SwapValueByPointer(d, "/hello", x);
|
||||||
|
|
||||||
|
bool success = EraseValueByPointer(d, "/a");
|
||||||
|
assert(success);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The conventions are shown here for comparison:
|
The conventions are shown here for comparison:
|
||||||
@ -166,6 +175,8 @@ private:
|
|||||||
};
|
};
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
`Erase()` or `EraseValueByPointer()` does not need allocator. And they return `true` if the value is erased successfully.
|
||||||
|
|
||||||
# Error Handling {#ErrorHandling}
|
# Error Handling {#ErrorHandling}
|
||||||
|
|
||||||
A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns false. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information.
|
A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns false. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information.
|
||||||
|
@ -304,7 +304,7 @@ public:
|
|||||||
RAPIDJSON_ASSERT(IsValid());
|
RAPIDJSON_ASSERT(IsValid());
|
||||||
ValueType* v = &root;
|
ValueType* v = &root;
|
||||||
bool exist = true;
|
bool exist = true;
|
||||||
for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
||||||
if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
|
if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
|
||||||
v->PushBack(Value().Move(), allocator);
|
v->PushBack(Value().Move(), allocator);
|
||||||
v = &((*v)[v->Size() - 1]);
|
v = &((*v)[v->Size() - 1]);
|
||||||
@ -373,7 +373,7 @@ public:
|
|||||||
ValueType* Get(ValueType& root) const {
|
ValueType* Get(ValueType& root) const {
|
||||||
RAPIDJSON_ASSERT(IsValid());
|
RAPIDJSON_ASSERT(IsValid());
|
||||||
ValueType* v = &root;
|
ValueType* v = &root;
|
||||||
for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
||||||
switch (v->GetType()) {
|
switch (v->GetType()) {
|
||||||
case kObjectType:
|
case kObjectType:
|
||||||
{
|
{
|
||||||
@ -588,6 +588,50 @@ public:
|
|||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
//! Erase a value in a subtree.
|
||||||
|
/*!
|
||||||
|
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
|
||||||
|
\return Whether the resolved value is found and erased.
|
||||||
|
|
||||||
|
\note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
|
||||||
|
*/
|
||||||
|
bool Erase(ValueType& root) const {
|
||||||
|
RAPIDJSON_ASSERT(IsValid());
|
||||||
|
if (tokenCount_ == 0) // Cannot erase the root
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ValueType* v = &root;
|
||||||
|
const Token* last = tokens_ + (tokenCount_ - 1);
|
||||||
|
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
||||||
|
switch (v->GetType()) {
|
||||||
|
case kObjectType:
|
||||||
|
{
|
||||||
|
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
||||||
|
if (m == v->MemberEnd())
|
||||||
|
return false;
|
||||||
|
if (t == last) {
|
||||||
|
v->EraseMember(m);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
v = &m->value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kArrayType:
|
||||||
|
if (t->index == kPointerInvalidIndex || t->index >= v->Size())
|
||||||
|
return false;
|
||||||
|
if (t == last) {
|
||||||
|
v->Erase(v->Begin() + t->index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
v = &((*v)[t->index]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Check whether a character should be percent-encoded.
|
//! Check whether a character should be percent-encoded.
|
||||||
/*!
|
/*!
|
||||||
@ -1131,6 +1175,18 @@ typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, con
|
|||||||
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
|
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
|
||||||
|
return pointer.Erase(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename CharType, size_t N>
|
||||||
|
bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
|
||||||
|
return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
|
||||||
|
}
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
@ -818,6 +818,21 @@ TEST(Pointer, Swap_NoAllocator) {
|
|||||||
EXPECT_STREQ("bar", d["foo"][1].GetString());
|
EXPECT_STREQ("bar", d["foo"][1].GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Pointer, Erase) {
|
||||||
|
Document d;
|
||||||
|
d.Parse(kJson);
|
||||||
|
|
||||||
|
EXPECT_FALSE(Pointer("").Erase(d));
|
||||||
|
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
|
||||||
|
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
|
||||||
|
EXPECT_EQ(1u, d["foo"].Size());
|
||||||
|
EXPECT_STREQ("baz", d["foo"][0].GetString());
|
||||||
|
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
|
||||||
|
EXPECT_TRUE(d["foo"].Empty());
|
||||||
|
EXPECT_TRUE(Pointer("/foo").Erase(d));
|
||||||
|
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Pointer, CreateValueByPointer) {
|
TEST(Pointer, CreateValueByPointer) {
|
||||||
Document d;
|
Document d;
|
||||||
Document::AllocatorType& a = d.GetAllocator();
|
Document::AllocatorType& a = d.GetAllocator();
|
||||||
@ -1319,6 +1334,36 @@ TEST(Pointer, SwapValueByPointer_NoAllocator) {
|
|||||||
EXPECT_STREQ("baz", d["foo"][1].GetString());
|
EXPECT_STREQ("baz", d["foo"][1].GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Pointer, EraseValueByPointer_Pointer) {
|
||||||
|
Document d;
|
||||||
|
d.Parse(kJson);
|
||||||
|
|
||||||
|
EXPECT_FALSE(EraseValueByPointer(d, Pointer("")));
|
||||||
|
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
|
||||||
|
EXPECT_EQ(1u, d["foo"].Size());
|
||||||
|
EXPECT_STREQ("baz", d["foo"][0].GetString());
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
|
||||||
|
EXPECT_TRUE(d["foo"].Empty());
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo")));
|
||||||
|
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pointer, EraseValueByPointer_String) {
|
||||||
|
Document d;
|
||||||
|
d.Parse(kJson);
|
||||||
|
|
||||||
|
EXPECT_FALSE(EraseValueByPointer(d, ""));
|
||||||
|
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
|
||||||
|
EXPECT_EQ(1u, d["foo"].Size());
|
||||||
|
EXPECT_STREQ("baz", d["foo"][0].GetString());
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
|
||||||
|
EXPECT_TRUE(d["foo"].Empty());
|
||||||
|
EXPECT_TRUE(EraseValueByPointer(d, "/foo"));
|
||||||
|
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Pointer, Ambiguity) {
|
TEST(Pointer, Ambiguity) {
|
||||||
{
|
{
|
||||||
Document d;
|
Document d;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user