Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
畅游知识海洋
json
提交
70fc5835
J
json
项目概览
畅游知识海洋
/
json
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
json
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
70fc5835
编写于
4月 18, 2016
作者:
N
Niels
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
started implementing JSON Patch (RFC 6902)
上级
3ca1bfdd
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
416 addition
and
0 deletion
+416
-0
src/json.hpp
src/json.hpp
+95
-0
src/json.hpp.re2c
src/json.hpp.re2c
+95
-0
test/unit.cpp
test/unit.cpp
+226
-0
未找到文件。
src/json.hpp
浏览文件 @
70fc5835
...
...
@@ -9492,6 +9492,101 @@ basic_json_parser_63:
}
/// @}
/*!
@brief applies a JSON patch
@param[in] patch JSON patch document
@return patched document
@note The original JSON value is not changed; that is, the patch is
applied to a copy of the value.
@sa [RFC 6902](https://tools.ietf.org/html/rfc6902)
*/
basic_json
apply_patch
(
const
basic_json
&
patch
)
const
{
basic_json
result
=
*
this
;
if
(
not
patch
.
is_array
())
{
// a JSON patch must be an array of objects
throw
std
::
domain_error
(
"JSON patch must be an array of objects"
);
}
for
(
const
auto
&
val
:
patch
)
{
if
(
not
val
.
is_object
())
{
throw
std
::
domain_error
(
"JSON patch must be an array of objects"
);
}
// collect members
const
auto
it_op
=
val
.
m_value
.
object
->
find
(
"op"
);
const
auto
it_path
=
val
.
m_value
.
object
->
find
(
"path"
);
const
auto
it_value
=
val
.
m_value
.
object
->
find
(
"value"
);
if
(
it_op
==
val
.
m_value
.
object
->
end
()
or
not
it_op
->
second
.
is_string
())
{
throw
std
::
domain_error
(
"operation must have a string 'op' member"
);
}
if
(
it_path
==
val
.
m_value
.
object
->
end
()
or
not
it_op
->
second
.
is_string
())
{
throw
std
::
domain_error
(
"operation must have a string 'path' member"
);
}
const
std
::
string
op
=
it_op
->
second
;
const
std
::
string
path
=
it_path
->
second
;
const
json_pointer
ptr
(
path
);
if
(
op
==
"add"
)
{
if
(
it_value
==
val
.
m_value
.
object
->
end
())
{
throw
std
::
domain_error
(
"'add' operation must have member 'value'"
);
}
result
[
ptr
]
=
it_value
->
second
;
}
else
if
(
op
==
"remove"
)
{
}
else
if
(
op
==
"replace"
)
{
if
(
it_value
==
val
.
m_value
.
object
->
end
())
{
throw
std
::
domain_error
(
"'replace' operation must have member 'value'"
);
}
}
else
if
(
op
==
"move"
)
{
}
else
if
(
op
==
"copy"
)
{
}
else
if
(
op
==
"test"
)
{
if
(
it_value
==
val
.
m_value
.
object
->
end
())
{
throw
std
::
domain_error
(
"'test' operation must have member 'value'"
);
}
if
(
result
.
at
(
ptr
)
!=
it_value
->
second
)
{
throw
std
::
domain_error
(
"unsuccessful: "
+
val
.
dump
());
}
}
else
{
// op must be "add", "remove", "replace", "move",
// "copy", or "test"
throw
std
::
domain_error
(
"operation value '"
+
op
+
"' is invalid"
);
}
}
return
result
;
}
};
...
...
src/json.hpp.re2c
浏览文件 @
70fc5835
...
...
@@ -8802,6 +8802,101 @@ class basic_json
}
/// @}
/*!
@brief applies a JSON patch
@param[in] patch JSON patch document
@return patched document
@note The original JSON value is not changed; that is, the patch is
applied to a copy of the value.
@sa [RFC 6902](https://tools.ietf.org/html/rfc6902)
*/
basic_json apply_patch(const basic_json& patch) const
{
basic_json result = *this;
if (not patch.is_array())
{
// a JSON patch must be an array of objects
throw std::domain_error("JSON patch must be an array of objects");
}
for (const auto& val : patch)
{
if (not val.is_object())
{
throw std::domain_error("JSON patch must be an array of objects");
}
// collect members
const auto it_op = val.m_value.object->find("op");
const auto it_path = val.m_value.object->find("path");
const auto it_value = val.m_value.object->find("value");
if (it_op == val.m_value.object->end() or not it_op->second.is_string())
{
throw std::domain_error("operation must have a string 'op' member");
}
if (it_path == val.m_value.object->end() or not it_op->second.is_string())
{
throw std::domain_error("operation must have a string 'path' member");
}
const std::string op = it_op->second;
const std::string path = it_path->second;
const json_pointer ptr(path);
if (op == "add")
{
if (it_value == val.m_value.object->end())
{
throw std::domain_error("'add' operation must have member 'value'");
}
result[ptr] = it_value->second;
}
else if (op == "remove")
{
}
else if (op == "replace")
{
if (it_value == val.m_value.object->end())
{
throw std::domain_error("'replace' operation must have member 'value'");
}
}
else if (op == "move")
{
}
else if (op == "copy")
{
}
else if (op == "test")
{
if (it_value == val.m_value.object->end())
{
throw std::domain_error("'test' operation must have member 'value'");
}
if (result.at(ptr) != it_value->second)
{
throw std::domain_error("unsuccessful: " + val.dump());
}
}
else
{
// op must be "add", "remove", "replace", "move",
// "copy", or "test"
throw std::domain_error("operation value '" + op + "' is invalid");
}
}
return result;
}
};
...
...
test/unit.cpp
浏览文件 @
70fc5835
...
...
@@ -12391,6 +12391,232 @@ TEST_CASE("JSON pointers")
}
}
TEST_CASE
(
"JSON patch"
)
{
SECTION
(
"examples from RFC 6902"
)
{
SECTION
(
"example A.1 - Adding an Object Member"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "foo": "bar"}
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{ "op": "add", "path": "/baz", "value": "qux" }
]
)"
_json
;
// The resulting JSON document:
json
expected
=
R"(
{
"baz": "qux",
"foo": "bar"
}
)"
_json
;
// check if patched value is as expected
CHECK
(
doc
.
apply_patch
(
patch
)
==
expected
);
}
SECTION
(
"example A.8 - Testing a Value: Success"
)
{
// An example target JSON document:
json
doc
=
R"(
{
"baz": "qux",
"foo": [ "a", 2, "c" ]
}
)"
_json
;
// A JSON Patch document that will result in successful evaluation:
json
patch
=
R"(
[
{ "op": "test", "path": "/baz", "value": "qux" },
{ "op": "test", "path": "/foo/1", "value": 2 }
]
)"
_json
;
// check if evaluation does not throw
CHECK_NOTHROW
(
doc
.
apply_patch
(
patch
));
// check if patched document is unchanged
CHECK
(
doc
.
apply_patch
(
patch
)
==
doc
);
}
SECTION
(
"example A.9 - Testing a Value: Error"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "baz": "qux" }
)"
_json
;
// A JSON Patch document that will result in an error condition:
json
patch
=
R"(
[
{ "op": "test", "path": "/baz", "value": "bar" }
]
)"
_json
;
// check that evaluation throws
CHECK_THROWS_AS
(
doc
.
apply_patch
(
patch
),
std
::
domain_error
);
CHECK_THROWS_WITH
(
doc
.
apply_patch
(
patch
),
"unsuccessful: "
+
patch
[
0
].
dump
());
}
SECTION
(
"example A.10 - Adding a Nested Member Object"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "foo": "bar" }
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{ "op": "add", "path": "/child", "value": { "grandchild": { } } }
]
)"
_json
;
// The resulting JSON document:
json
expected
=
R"(
{
"foo": "bar",
"child": {
"grandchild": {
}
}
}
)"
_json
;
// check if patched value is as expected
CHECK
(
doc
.
apply_patch
(
patch
)
==
expected
);
}
SECTION
(
"example A.11 - Ignoring Unrecognized Elements"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "foo": "bar" }
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
]
)"
_json
;
json
expected
=
R"(
{
"foo": "bar",
"baz": "qux"
}
)"
_json
;
// check if patched value is as expected
CHECK
(
doc
.
apply_patch
(
patch
)
==
expected
);
}
SECTION
(
"example A.12 - Adding to a Nonexistent Target"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "foo": "bar" }
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{ "op": "add", "path": "/baz/bat", "value": "qux" }
]
)"
_json
;
// This JSON Patch document, applied to the target JSON document
// above, would result in an error (therefore, it would not be
// applied), because the "add" operation's target location that
// references neither the root of the document, nor a member of
// an existing object, nor a member of an existing array.
CHECK_THROWS_AS
(
doc
.
apply_patch
(
patch
),
std
::
out_of_range
);
CHECK_THROWS_WITH
(
doc
.
apply_patch
(
patch
),
"unresolved reference token 'bat'"
);
}
SECTION
(
"example A.14 - Escape Ordering"
)
{
// An example target JSON document:
json
doc
=
R"(
{
"/": 9,
"~1": 10
}
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{"op": "test", "path": "/~01", "value": 10}
]
)"
_json
;
json
expected
=
R"(
{
"/": 9,
"~1": 10
}
)"
_json
;
// check if patched value is as expected
CHECK
(
doc
.
apply_patch
(
patch
)
==
expected
);
}
SECTION
(
"example A.15 - Comparing Strings and Numbers"
)
{
// An example target JSON document:
json
doc
=
R"(
{
"/": 9,
"~1": 10
}
)"
_json
;
// A JSON Patch document that will result in an error condition:
json
patch
=
R"(
[
{"op": "test", "path": "/~01", "value": "10"}
]
)"
_json
;
// check that evaluation throws
CHECK_THROWS_AS
(
doc
.
apply_patch
(
patch
),
std
::
domain_error
);
CHECK_THROWS_WITH
(
doc
.
apply_patch
(
patch
),
"unsuccessful: "
+
patch
[
0
].
dump
());
}
SECTION
(
"example A.16 - Adding an Array Value"
)
{
// An example target JSON document:
json
doc
=
R"(
{ "foo": ["bar"] }
)"
_json
;
// A JSON Patch document:
json
patch
=
R"(
[
{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
]
)"
_json
;
// The resulting JSON document:
json
expected
=
R"(
{ "foo": ["bar", ["abc", "def"]] }
)"
_json
;
// check if patched value is as expected
CHECK
(
doc
.
apply_patch
(
patch
)
==
expected
);
}
}
}
TEST_CASE
(
"regression tests"
)
{
SECTION
(
"issue #60 - Double quotation mark is not parsed correctly"
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录