aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/apiref.rst7
-rw-r--r--src/dump.c99
-rw-r--r--src/jansson.h1
-rw-r--r--test/bin/json_process.c3
-rwxr-xr-xtest/suites/encoding-flags/run32
-rw-r--r--test/suites/encoding-flags/sort-keys/env1
-rw-r--r--test/suites/encoding-flags/sort-keys/input1
-rw-r--r--test/suites/encoding-flags/sort-keys/output1
8 files changed, 132 insertions, 13 deletions
diff --git a/doc/apiref.rst b/doc/apiref.rst
index dcd401c..fd2a7c9 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -526,6 +526,13 @@ can be ORed together to obtain *flags*.
.. versionadded:: 1.2
+``JSON_SORT_KEYS``
+ If this flag is used, all the objects in output are sorted by key.
+ This is useful e.g. if two JSON texts are diffed or visually
+ compared.
+
+ .. versionadded:: 1.2
+
The following functions perform the actual JSON encoding. The result
is in UTF-8.
diff --git a/src/dump.c b/src/dump.c
index dc3fcbc..328e93b 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
+#include <assert.h>
#include <jansson.h>
#include "jansson_private.h"
@@ -153,6 +154,11 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
return dump("\"", 1, data);
}
+static int object_key_cmp(const void *key1, const void *key2)
+{
+ return strcmp(*(const char **)key1, *(const char **)key2);
+}
+
static int do_dump(const json_t *json, unsigned long flags, int depth,
dump_func dump, void *data)
{
@@ -269,29 +275,96 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
if(dump_indent(flags, depth + 1, 0, dump, data))
return -1;
- while(iter)
+ if(flags & JSON_SORT_KEYS)
{
- void *next = json_object_iter_next((json_t *)json, iter);
+ /* Sort keys */
- dump_string(json_object_iter_key(iter), ascii, dump, data);
- if(dump(separator, separator_length, data) ||
- do_dump(json_object_iter_value(iter), flags, depth + 1,
- dump, data))
+ const char **keys;
+ unsigned int size;
+ unsigned int i;
+
+ size = json_object_size(json);
+ keys = malloc(size * sizeof(const char *));
+ if(!keys)
return -1;
- if(next)
+ i = 0;
+ while(iter)
{
- if(dump(",", 1, data) ||
- dump_indent(flags, depth + 1, 1, dump, data))
- return -1;
+ keys[i] = json_object_iter_key(iter);
+ iter = json_object_iter_next((json_t *)json, iter);
+ i++;
}
- else
+ assert(i == size);
+
+ qsort(keys, size, sizeof(const char *), object_key_cmp);
+
+ for(i = 0; i < size; i++)
{
- if(dump_indent(flags, depth, 0, dump, data))
+ const char *key;
+ json_t *value;
+
+ key = keys[i];
+ value = json_object_get(json, key);
+ assert(value);
+
+ dump_string(key, ascii, dump, data);
+ if(dump(separator, separator_length, data) ||
+ do_dump(value, flags, depth + 1, dump, data))
+ {
+ free(keys);
return -1;
+ }
+
+ if(i < size - 1)
+ {
+ if(dump(",", 1, data) ||
+ dump_indent(flags, depth + 1, 1, dump, data))
+ {
+ free(keys);
+ return -1;
+ }
+ }
+ else
+ {
+ if(dump_indent(flags, depth, 0, dump, data))
+ {
+ free(keys);
+ return -1;
+ }
+ }
}
- iter = next;
+ free(keys);
+ }
+ else
+ {
+ /* Don't sort keys */
+
+ while(iter)
+ {
+ void *next = json_object_iter_next((json_t *)json, iter);
+
+ dump_string(json_object_iter_key(iter), ascii, dump, data);
+ if(dump(separator, separator_length, data) ||
+ do_dump(json_object_iter_value(iter), flags, depth + 1,
+ dump, data))
+ return -1;
+
+ if(next)
+ {
+ if(dump(",", 1, data) ||
+ dump_indent(flags, depth + 1, 1, dump, data))
+ return -1;
+ }
+ else
+ {
+ if(dump_indent(flags, depth, 0, dump, data))
+ return -1;
+ }
+
+ iter = next;
+ }
}
object->visited = 0;
diff --git a/src/jansson.h b/src/jansson.h
index d59fe10..607dfb5 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -144,6 +144,7 @@ json_t *json_load_file(const char *path, json_error_t *error);
#define JSON_INDENT(n) (n & 0xFF)
#define JSON_COMPACT 0x100
#define JSON_ENSURE_ASCII 0x200
+#define JSON_SORT_KEYS 0x400
char *json_dumps(const json_t *json, unsigned long flags);
int json_dumpf(const json_t *json, FILE *output, unsigned long flags);
diff --git a/test/bin/json_process.c b/test/bin/json_process.c
index e7be614..794e307 100644
--- a/test/bin/json_process.c
+++ b/test/bin/json_process.c
@@ -53,6 +53,9 @@ int main(int argc, char *argv[])
if(getenv_int("JSON_ENSURE_ASCII"))
flags |= JSON_ENSURE_ASCII;
+ if(getenv_int("JSON_SORT_KEYS"))
+ flags |= JSON_SORT_KEYS;
+
json = json_loadf(stdin, &error);
if(!json) {
fprintf(stderr, "%d\n%s\n", error.line, error.text);
diff --git a/test/suites/encoding-flags/run b/test/suites/encoding-flags/run
new file mode 100755
index 0000000..a65fe5b
--- /dev/null
+++ b/test/suites/encoding-flags/run
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+is_test() {
+ test -d $test_path
+}
+
+run_test() {
+ (
+ if [ -f $test_path/env ]; then
+ . $test_path/env
+ fi
+ $json_process <$test_path/input >$test_log/stdout 2>$test_log/stderr
+ )
+ valgrind_check $test_log/stderr || return 1
+ cmp -s $test_path/output $test_log/stdout
+}
+
+show_error() {
+ valgrind_show_error && return
+
+ echo "EXPECTED OUTPUT:"
+ nl -bn $test_path/output
+ echo "ACTUAL OUTPUT:"
+ nl -bn $test_log/stdout
+}
+
+. $top_srcdir/test/scripts/run-tests.sh
diff --git a/test/suites/encoding-flags/sort-keys/env b/test/suites/encoding-flags/sort-keys/env
new file mode 100644
index 0000000..00529e7
--- /dev/null
+++ b/test/suites/encoding-flags/sort-keys/env
@@ -0,0 +1 @@
+export JSON_SORT_KEYS=1
diff --git a/test/suites/encoding-flags/sort-keys/input b/test/suites/encoding-flags/sort-keys/input
new file mode 100644
index 0000000..66951d6
--- /dev/null
+++ b/test/suites/encoding-flags/sort-keys/input
@@ -0,0 +1 @@
+{"foo": 1, "bar": 2, "baz": 3, "quux": 4}
diff --git a/test/suites/encoding-flags/sort-keys/output b/test/suites/encoding-flags/sort-keys/output
new file mode 100644
index 0000000..132d9df
--- /dev/null
+++ b/test/suites/encoding-flags/sort-keys/output
@@ -0,0 +1 @@
+{"bar": 2, "baz": 3, "foo": 1, "quux": 4} \ No newline at end of file