mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
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: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
ccff335f83
commit
547a7c778a
@ -1427,6 +1427,7 @@ virJSONValueObjectGetValue;
|
|||||||
virJSONValueObjectHasKey;
|
virJSONValueObjectHasKey;
|
||||||
virJSONValueObjectIsNull;
|
virJSONValueObjectIsNull;
|
||||||
virJSONValueObjectKeysNumber;
|
virJSONValueObjectKeysNumber;
|
||||||
|
virJSONValueObjectRemoveKey;
|
||||||
virJSONValueToString;
|
virJSONValueToString;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* virjson.c: JSON object parsing/formatting
|
* 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
|
* Copyright (C) 2009 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* 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;
|
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)
|
virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n)
|
||||||
{
|
{
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* virjson.h: JSON object parsing/formatting
|
* 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
|
* Copyright (C) 2009 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -55,12 +55,12 @@ struct _virJSONObjectPair {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct _virJSONObject {
|
struct _virJSONObject {
|
||||||
unsigned int npairs;
|
size_t npairs;
|
||||||
virJSONObjectPairPtr pairs;
|
virJSONObjectPairPtr pairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _virJSONArray {
|
struct _virJSONArray {
|
||||||
unsigned int nvalues;
|
size_t nvalues;
|
||||||
virJSONValuePtr *values;
|
virJSONValuePtr *values;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,6 +131,10 @@ int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key
|
|||||||
int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean);
|
int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean);
|
||||||
int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key);
|
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);
|
virJSONValuePtr virJSONValueFromString(const char *jsonstring);
|
||||||
char *virJSONValueToString(virJSONValuePtr object,
|
char *virJSONValueToString(virJSONValuePtr object,
|
||||||
bool pretty);
|
bool pretty);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
struct testInfo {
|
struct testInfo {
|
||||||
const char *doc;
|
const char *doc;
|
||||||
|
const char *expect;
|
||||||
bool pass;
|
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
|
static int
|
||||||
mymain(void)
|
mymain(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
#define DO_TEST_FULL(name, cmd, doc, pass) \
|
#define DO_TEST_FULL(name, cmd, doc, expect, pass) \
|
||||||
do { \
|
do { \
|
||||||
struct testInfo info = { doc, pass }; \
|
struct testInfo info = { doc, expect, pass }; \
|
||||||
if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0) \
|
if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0) \
|
||||||
ret = -1; \
|
ret = -1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DO_TEST_PARSE(name, doc) \
|
#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("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}");
|
||||||
DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
|
DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
|
||||||
@ -105,6 +175,13 @@ mymain(void)
|
|||||||
"\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
|
"\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
|
||||||
"\"query-balloon\"}], \"id\": \"libvirt-2\"}");
|
"\"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;
|
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user