提交 547a7c77 编写于 作者: E Eric Blake

json: support removing a value from an object

In an upcoming patch, I need the way to safely transfer a nested
virJSON object out of its parent container for independent use,
even after the parent is freed.

* src/util/virjson.h (virJSONValueObjectRemoveKey): New function.
(_virJSONObject, _virJSONArray): Use correct type.
* src/util/virjson.c (virJSONValueObjectRemoveKey): Implement it.
* src/libvirt_private.syms (virjson.h): Export it.
* tests/jsontest.c (mymain): Test it.
Signed-off-by: NEric Blake <eblake@redhat.com>
上级 ccff335f
......@@ -1427,6 +1427,7 @@ virJSONValueObjectGetValue;
virJSONValueObjectHasKey;
virJSONValueObjectIsNull;
virJSONValueObjectKeysNumber;
virJSONValueObjectRemoveKey;
virJSONValueToString;
......
/*
* virjson.c: JSON object parsing/formatting
*
* Copyright (C) 2009-2010, 2012 Red Hat, Inc.
* Copyright (C) 2009-2010, 2012-2013 Red Hat, Inc.
* Copyright (C) 2009 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
......@@ -448,6 +448,38 @@ const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n)
return object->data.object.pairs[n].key;
}
/* Remove the key-value pair tied to @key out of @object. If @value is
* not NULL, the dropped value object is returned instead of freed.
* Returns 1 on success, 0 if no key was found, and -1 on error. */
int
virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key,
virJSONValuePtr *value)
{
int i;
if (value)
*value = NULL;
if (object->type != VIR_JSON_TYPE_OBJECT)
return -1;
for (i = 0 ; i < object->data.object.npairs ; i++) {
if (STREQ(object->data.object.pairs[i].key, key)) {
if (value) {
*value = object->data.object.pairs[i].value;
object->data.object.pairs[i].value = NULL;
}
VIR_FREE(object->data.object.pairs[i].key);
virJSONValueFree(object->data.object.pairs[i].value);
VIR_DELETE_ELEMENT(object->data.object.pairs, i,
object->data.object.npairs);
return 1;
}
}
return 0;
}
virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n)
{
if (object->type != VIR_JSON_TYPE_OBJECT)
......
/*
* virjson.h: JSON object parsing/formatting
*
* Copyright (C) 2009, 2012 Red Hat, Inc.
* Copyright (C) 2009, 2012-2013 Red Hat, Inc.
* Copyright (C) 2009 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
......@@ -55,12 +55,12 @@ struct _virJSONObjectPair {
};
struct _virJSONObject {
unsigned int npairs;
size_t npairs;
virJSONObjectPairPtr pairs;
};
struct _virJSONArray {
unsigned int nvalues;
size_t nvalues;
virJSONValuePtr *values;
};
......@@ -131,6 +131,10 @@ int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key
int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean);
int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key);
int virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key,
virJSONValuePtr *value)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
virJSONValuePtr virJSONValueFromString(const char *jsonstring);
char *virJSONValueToString(virJSONValuePtr object,
bool pretty);
......
......@@ -11,6 +11,7 @@
struct testInfo {
const char *doc;
const char *expect;
bool pass;
};
......@@ -54,20 +55,89 @@ cleanup:
}
static int
testJSONAddRemove(const void *data)
{
const struct testInfo *info = data;
virJSONValuePtr json;
virJSONValuePtr name;
char *result = NULL;
int ret = -1;
json = virJSONValueFromString(info->doc);
switch (virJSONValueObjectRemoveKey(json, "name", &name)) {
case 1:
if (!info->pass) {
if (virTestGetVerbose())
fprintf(stderr, "should not remove from non-object %s\n",
info->doc);
goto cleanup;
}
break;
case -1:
if (!info->pass)
ret = 0;
else if (virTestGetVerbose())
fprintf(stderr, "Fail to recognize non-object %s\n", info->doc);
goto cleanup;
default:
if (virTestGetVerbose())
fprintf(stderr, "unexpected result when removing from %s\n",
info->doc);
goto cleanup;
}
if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) {
if (virTestGetVerbose())
fprintf(stderr, "unexpected value after removing name: %s\n",
NULLSTR(virJSONValueGetString(name)));
goto cleanup;
}
if (virJSONValueObjectRemoveKey(json, "name", NULL)) {
if (virTestGetVerbose())
fprintf(stderr, "%s",
"unexpected success when removing missing key\n");
goto cleanup;
}
if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) {
if (virTestGetVerbose())
fprintf(stderr, "%s", "unexpected failure adding new key\n");
goto cleanup;
}
if (!(result = virJSONValueToString(json, false))) {
if (virTestGetVerbose())
fprintf(stderr, "%s", "failed to stringize result\n");
goto cleanup;
}
if (STRNEQ(info->expect, result)) {
if (virTestGetVerbose())
virtTestDifference(stderr, info->expect, result);
goto cleanup;
}
ret = 0;
cleanup:
virJSONValueFree(json);
virJSONValueFree(name);
VIR_FREE(result);
return ret;
}
static int
mymain(void)
{
int ret = 0;
#define DO_TEST_FULL(name, cmd, doc, pass) \
#define DO_TEST_FULL(name, cmd, doc, expect, pass) \
do { \
struct testInfo info = { doc, pass }; \
struct testInfo info = { doc, expect, pass }; \
if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0) \
ret = -1; \
} while (0)
#define DO_TEST_PARSE(name, doc) \
DO_TEST_FULL(name, FromString, doc, true)
DO_TEST_FULL(name, FromString, doc, NULL, true)
DO_TEST_PARSE("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}");
DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
......@@ -105,6 +175,13 @@ mymain(void)
"\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
"\"query-balloon\"}], \"id\": \"libvirt-2\"}");
DO_TEST_FULL("add and remove", AddRemove,
"{\"name\": \"sample\", \"value\": true}",
"{\"value\":true,\"newname\":\"foo\"}",
true);
DO_TEST_FULL("add and remove", AddRemove,
"[ 1 ]", NULL, false);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册