diff options
| author | Philipp Stephani | 2017-12-13 22:41:28 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2017-12-24 13:59:25 +0100 |
| commit | f552a957ada23a7ff182fc1ab94221ced3ed1713 (patch) | |
| tree | 359c39cfc24e3c166984717f73884f6c221d1378 /src | |
| parent | 3455192777459a08a38b0adb311a76202e29f48d (diff) | |
| download | emacs-f552a957ada23a7ff182fc1ab94221ced3ed1713.tar.gz emacs-f552a957ada23a7ff182fc1ab94221ced3ed1713.zip | |
Accept alists when serializing JSON
* src/json.c (lisp_to_json_toplevel_1): Also accept alists
representing objects.
* src/json.c (Fjson_serialize): Update docstring.
* test/src/json-tests.el (json-serialize/object): Add unit tests for
serializing alists.
* doc/lispref/text.texi (Parsing JSON): Document that serialization
functions accept alists.
Diffstat (limited to 'src')
| -rw-r--r-- | src/json.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/src/json.c b/src/json.c index c1daba199c3..f615c4269f1 100644 --- a/src/json.c +++ b/src/json.c | |||
| @@ -367,12 +367,48 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) | |||
| 367 | clear_unwind_protect (count); | 367 | clear_unwind_protect (count); |
| 368 | return unbind_to (count, Qnil); | 368 | return unbind_to (count, Qnil); |
| 369 | } | 369 | } |
| 370 | else if (NILP (lisp)) | ||
| 371 | { | ||
| 372 | *json = json_check (json_object ()); | ||
| 373 | return Qnil; | ||
| 374 | } | ||
| 375 | else if (CONSP (lisp)) | ||
| 376 | { | ||
| 377 | Lisp_Object tail = lisp; | ||
| 378 | *json = json_check (json_object ()); | ||
| 379 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 380 | record_unwind_protect_ptr (json_release_object, *json); | ||
| 381 | FOR_EACH_TAIL (tail) | ||
| 382 | { | ||
| 383 | Lisp_Object pair = XCAR (tail); | ||
| 384 | CHECK_CONS (pair); | ||
| 385 | Lisp_Object key_symbol = XCAR (pair); | ||
| 386 | Lisp_Object value = XCDR (pair); | ||
| 387 | CHECK_SYMBOL (key_symbol); | ||
| 388 | Lisp_Object key = SYMBOL_NAME (key_symbol); | ||
| 389 | /* We can't specify the length, so the string must be | ||
| 390 | null-terminated. */ | ||
| 391 | check_string_without_embedded_nulls (key); | ||
| 392 | const char *key_str = SSDATA (key); | ||
| 393 | /* Only add element if key is not already present. */ | ||
| 394 | if (json_object_get (*json, key_str) == NULL) | ||
| 395 | { | ||
| 396 | int status | ||
| 397 | = json_object_set_new (*json, key_str, lisp_to_json (value)); | ||
| 398 | if (status == -1) | ||
| 399 | json_out_of_memory (); | ||
| 400 | } | ||
| 401 | } | ||
| 402 | CHECK_LIST_END (tail, lisp); | ||
| 403 | clear_unwind_protect (count); | ||
| 404 | return unbind_to (count, Qnil); | ||
| 405 | } | ||
| 370 | wrong_type_argument (Qjson_value_p, lisp); | 406 | wrong_type_argument (Qjson_value_p, lisp); |
| 371 | } | 407 | } |
| 372 | 408 | ||
| 373 | /* Convert LISP to a toplevel JSON object (array or object). Signal | 409 | /* Convert LISP to a toplevel JSON object (array or object). Signal |
| 374 | an error of type `wrong-type-argument' if LISP is not a vector or | 410 | an error of type `wrong-type-argument' if LISP is not a vector, |
| 375 | hashtable. */ | 411 | hashtable, or alist. */ |
| 376 | 412 | ||
| 377 | static json_t * | 413 | static json_t * |
| 378 | lisp_to_json_toplevel (Lisp_Object lisp) | 414 | lisp_to_json_toplevel (Lisp_Object lisp) |
| @@ -413,19 +449,20 @@ lisp_to_json (Lisp_Object lisp) | |||
| 413 | return json_check (json_stringn (SSDATA (encoded), SBYTES (encoded))); | 449 | return json_check (json_stringn (SSDATA (encoded), SBYTES (encoded))); |
| 414 | } | 450 | } |
| 415 | 451 | ||
| 416 | /* LISP now must be a vector or hashtable. */ | 452 | /* LISP now must be a vector, hashtable, or alist. */ |
| 417 | return lisp_to_json_toplevel (lisp); | 453 | return lisp_to_json_toplevel (lisp); |
| 418 | } | 454 | } |
| 419 | 455 | ||
| 420 | DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, | 456 | DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, |
| 421 | doc: /* Return the JSON representation of OBJECT as a string. | 457 | doc: /* Return the JSON representation of OBJECT as a string. |
| 422 | OBJECT must be a vector or hashtable, and its elements can recursively | 458 | OBJECT must be a vector, hashtable, or alist, and its elements can |
| 423 | contain `:null', `:false', t, numbers, strings, or other vectors and | 459 | recursively contain `:null', `:false', t, numbers, strings, or other |
| 424 | hashtables. `:null', `:false', and t will be converted to JSON null, | 460 | vectors hashtables, and alist. `:null', `:false', and t will be |
| 425 | false, and true values, respectively. Vectors will be converted to | 461 | converted to JSON null, false, and true values, respectively. Vectors |
| 426 | JSON arrays, and hashtables to JSON objects. Hashtable keys must be | 462 | will be converted to JSON arrays, and hashtables and alists to JSON |
| 427 | strings without embedded null characters and must be unique within | 463 | objects. Hashtable keys must be strings without embedded null |
| 428 | each object. */) | 464 | characters and must be unique within each object. Alist keys must be |
| 465 | symbols; if a key is duplicate, the first instance is used. */) | ||
| 429 | (Lisp_Object object) | 466 | (Lisp_Object object) |
| 430 | { | 467 | { |
| 431 | ptrdiff_t count = SPECPDL_INDEX (); | 468 | ptrdiff_t count = SPECPDL_INDEX (); |