As it turns out sometimes users pass in an arbitrarily nested structure
e.g. for the qemu backing chains JSON pseudo protocol. This new
implementation deflatens now a single object fully even with nested
keys.
Additionally it's not necessary now to stick with the "file." prefix for
the properties.
---
src/util/virjson.c | 67 ++++++++++++++++------
tests/virjsondata/deflatten-basic-generic-out.json | 20 +++++++
.../deflatten-concat-double-key-out.json | 9 ---
tests/virjsondata/deflatten-concat-out.json | 7 +--
tests/virjsondata/deflatten-deep-file-out.json | 24 ++++++--
tests/virjsondata/deflatten-deep-generic-out.json | 27 +++++++++
tests/virjsondata/deflatten-double-key-out.json | 6 --
tests/virjsontest.c | 8 +--
8 files changed, 121 insertions(+), 47 deletions(-)
create mode 100644 tests/virjsondata/deflatten-basic-generic-out.json
delete mode 100644 tests/virjsondata/deflatten-concat-double-key-out.json
create mode 100644 tests/virjsondata/deflatten-deep-generic-out.json
delete mode 100644 tests/virjsondata/deflatten-double-key-out.json
diff --git a/src/util/virjson.c b/src/util/virjson.c
index a8e28cd1b..635b78e3a 100644
--- a/src/util/virjson.c
+++ b/src/util/virjson.c
@@ -1974,23 +1974,60 @@ virJSONValueObjectDeflattenWorker(const char *key,
{
virJSONValuePtr retobj = opaque;
virJSONValuePtr newval = NULL;
- const char *newkey;
+ virJSONValuePtr existobj;
+ char **tokens = NULL;
+ size_t ntokens = 0;
+ int ret = -1;
- if (!(newkey = STRSKIP(key, "file."))) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("JSON object is neither nested nor flattened"));
- return -1;
+ /* non-nested keys only need to be copied */
+ if (!strchr(key, '.')) {
+ if (!(newval = virJSONValueCopy(value)))
+ return -1;
+
+ if (virJSONValueObjectHasKey(retobj, key)) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("can't deflatten colliding key '%s'"),
key);
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectAppend(retobj, key, newval) < 0)
+ goto cleanup;
+
+ return 0;
}
- if (!(newval = virJSONValueCopy(value)))
- return -1;
+ if (!(tokens = virStringSplitCount(key, ".", 2, &ntokens)))
+ goto cleanup;
- if (virJSONValueObjectAppend(retobj, newkey, newval) < 0) {
- virJSONValueFree(newval);
- return -1;
+ if (ntokens != 2) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid nested value key '%s'"), key);
+ goto cleanup;
}
- return 0;
+ if (!(existobj = virJSONValueObjectGet(retobj, tokens[0]))) {
+ if (!(existobj = virJSONValueNewObject()))
+ goto cleanup;
+
+ if (virJSONValueObjectAppend(retobj, tokens[0], existobj) < 0)
+ goto cleanup;
+
+ } else {
+ if (!virJSONValueIsObject(existobj)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("mixing nested objects and values is forbidden in
"
+ "JSON deflattening"));
+ goto cleanup;
+ }
+ }
+
+ ret = virJSONValueObjectDeflattenWorker(tokens[1], value, existobj);
+
+ cleanup:
+ virStringListFreeCount(tokens, ntokens);
+ virJSONValueFree(newval);
+
+ return ret;
}
@@ -2005,9 +2042,6 @@ virJSONValueObjectDeflattenWorker(const char *key,
* This function will attempt to reverse the process and provide a nested json
* hierarchy so that the parsers can be kept simple and we still can use the
* weird syntax some users might use.
- *
- * Currently this function will flatten out just the 'file.' prefix into a new
- * tree. Any other syntax will be rejected.
*/
virJSONValuePtr
virJSONValueObjectDeflatten(virJSONValuePtr json)
@@ -2023,10 +2057,7 @@ virJSONValueObjectDeflatten(virJSONValuePtr json)
deflattened) < 0)
goto cleanup;
- if (virJSONValueObjectCreate(&ret, "a:file", deflattened, NULL) <
0)
- goto cleanup;
-
- deflattened = NULL;
+ VIR_STEAL_PTR(ret, deflattened);
cleanup:
virJSONValueFree(deflattened);
diff --git a/tests/virjsondata/deflatten-basic-generic-out.json
b/tests/virjsondata/deflatten-basic-generic-out.json
new file mode 100644
index 000000000..ab639aa48
--- /dev/null
+++ b/tests/virjsondata/deflatten-basic-generic-out.json
@@ -0,0 +1,20 @@
+{
+ "foo": {
+ "int": 1,
+ "string": "string",
+ "object": {
+ "data": "value",
+ "foo": "bar"
+ }
+ },
+ "bar": {
+ "int": 1
+ },
+ "blurb": {
+ "string": "string",
+ "object": {
+ "data": "value",
+ "foo": "bar"
+ }
+ }
+}
diff --git a/tests/virjsondata/deflatten-concat-double-key-out.json
b/tests/virjsondata/deflatten-concat-double-key-out.json
deleted file mode 100644
index 5624ef123..000000000
--- a/tests/virjsondata/deflatten-concat-double-key-out.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "file": {
- "nest": {
- "into": "is already here"
- },
- "nest.into": 2,
- "nest.there": "too"
- }
-}
diff --git a/tests/virjsondata/deflatten-concat-out.json
b/tests/virjsondata/deflatten-concat-out.json
index 539d2cc30..be417e53a 100644
--- a/tests/virjsondata/deflatten-concat-out.json
+++ b/tests/virjsondata/deflatten-concat-out.json
@@ -1,9 +1,8 @@
{
"file": {
"nest": {
-
- },
- "nest.into": 2,
- "nest.there": "too"
+ "into": 2,
+ "there": "too"
+ }
}
}
diff --git a/tests/virjsondata/deflatten-deep-file-out.json
b/tests/virjsondata/deflatten-deep-file-out.json
index a5910c9f7..d4614eeaf 100644
--- a/tests/virjsondata/deflatten-deep-file-out.json
+++ b/tests/virjsondata/deflatten-deep-file-out.json
@@ -1,11 +1,23 @@
{
"file": {
- "double.nest1": "some",
- "double.nest2": "more",
- "double.nest3": {
- "even": "objects"
+ "double": {
+ "nest1": "some",
+ "nest2": "more",
+ "nest3": {
+ "even": "objects"
+ }
},
- "very.deeply.nested.object.chains.nest1": "some",
- "very.deeply.nested.object.chains.nest2": "stuff"
+ "very": {
+ "deeply": {
+ "nested": {
+ "object": {
+ "chains": {
+ "nest1": "some",
+ "nest2": "stuff"
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/tests/virjsondata/deflatten-deep-generic-out.json
b/tests/virjsondata/deflatten-deep-generic-out.json
new file mode 100644
index 000000000..7ea521a8f
--- /dev/null
+++ b/tests/virjsondata/deflatten-deep-generic-out.json
@@ -0,0 +1,27 @@
+{
+ "foo": {
+ "double": {
+ "nest1": "some",
+ "nest2": "more"
+ },
+ "very": {
+ "deeply": {
+ "nested": {
+ "object": {
+ "chains": {
+ "nest1": "some",
+ "nest2": "stuff"
+ }
+ }
+ }
+ }
+ }
+ },
+ "bar": {
+ "double": {
+ "nest3": {
+ "even": "objects"
+ }
+ }
+ }
+}
diff --git a/tests/virjsondata/deflatten-double-key-out.json
b/tests/virjsondata/deflatten-double-key-out.json
deleted file mode 100644
index ca6766e5b..000000000
--- a/tests/virjsondata/deflatten-double-key-out.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "file": {
- "nest": 1,
- "nest.into": 2
- }
-}
diff --git a/tests/virjsontest.c b/tests/virjsontest.c
index d69b22bf3..b3ce6591a 100644
--- a/tests/virjsontest.c
+++ b/tests/virjsontest.c
@@ -514,13 +514,13 @@ mymain(void)
DO_TEST_DEFLATTEN("unflattened", true);
DO_TEST_DEFLATTEN("basic-file", true);
- DO_TEST_DEFLATTEN("basic-generic", false);
+ DO_TEST_DEFLATTEN("basic-generic", true);
DO_TEST_DEFLATTEN("deep-file", true);
- DO_TEST_DEFLATTEN("deep-generic", false);
+ DO_TEST_DEFLATTEN("deep-generic", true);
DO_TEST_DEFLATTEN("nested", true);
- DO_TEST_DEFLATTEN("double-key", true);
+ DO_TEST_DEFLATTEN("double-key", false);
DO_TEST_DEFLATTEN("concat", true);
- DO_TEST_DEFLATTEN("concat-double-key", true);
+ DO_TEST_DEFLATTEN("concat-double-key", false);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.12.2