diff --git a/example/parse_config.c b/example/parse_config.c index acce032d..0e701926 100644 --- a/example/parse_config.c +++ b/example/parse_config.c @@ -34,20 +34,19 @@ main(void) /* read the entire config file */ rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); + /* file read error handling */ if (rd == 0 && !feof(stdin)) { fprintf(stderr, "error encountered on file read\n"); return 1; - } - - if (rd >= sizeof(fileData) - 1) { + } else if (rd >= sizeof(fileData) - 1) { fprintf(stderr, "config file too big\n"); return 1; } - /* we have the whole config file in memory. let's parse it */ + /* we have the whole config file in memory. let's parse it ... */ node = yajl_tree_parse((const char *) fileData, errbuf, sizeof(errbuf)); - /* error handling */ + /* parse error handling */ if (node == NULL) { fprintf(stderr, "parse_error: "); if (strlen(errbuf)) fprintf(stderr, " %s", errbuf); @@ -56,11 +55,11 @@ main(void) return 1; } - /* now extract a nested value from the config file */ + /* ... and extract a nested value from the config file */ { const char * path[] = { "Logging", "timeFormat", (const char *) 0 }; yajl_val v = yajl_tree_get(node, path, yajl_t_string); - if (v) printf("Logging/timeFomat: %s\n", YAJL_GET_STRING(v)); + if (v) printf("%s/%s: %s\n", path[0], path[1], YAJL_GET_STRING(v)); else printf("no such node: %s/%s\n", path[0], path[1]); } diff --git a/src/YAJL.dxy b/src/YAJL.dxy index 3bdae868..57c720c9 100644 --- a/src/YAJL.dxy +++ b/src/YAJL.dxy @@ -518,7 +518,7 @@ EXCLUDE_SYMBOLS = # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = .. # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/src/api/yajl_parse.h b/src/api/yajl_parse.h index 23be5847..55c83110 100644 --- a/src/api/yajl_parse.h +++ b/src/api/yajl_parse.h @@ -16,7 +16,7 @@ /** * \file yajl_parse.h - * Interface to YAJL's JSON parsing facilities. + * Interface to YAJL's JSON stream parsing facilities. */ #include @@ -57,15 +57,19 @@ extern "C" { * continue. If zero, the parse will be canceled and * yajl_status_client_canceled will be returned from the parse. * - * Note about handling of numbers: - * yajl will only convert numbers that can be represented in a double - * or a 64 bit (long long) int. All other numbers will be passed to the client - * in string form using the yajl_number callback. Furthermore, if - * yajl_number is not NULL, it will always be used to return numbers, - * that is yajl_integer and yajl_double will be ignored. If - * yajl_number is NULL but one of yajl_integer or yajl_double are - * defined, parsing of a number larger than is representable - * in a double or 64 bit integer will result in a parse error. + * \attention { + * A note about the handling of numbers: + * + * yajl will only convert numbers that can be represented in a + * double or a 64 bit (long long) int. All other numbers will + * be passed to the client in string form using the yajl_number + * callback. Furthermore, if yajl_number is not NULL, it will + * always be used to return numbers, that is yajl_integer and + * yajl_double will be ignored. If yajl_number is NULL but one + * of yajl_integer or yajl_double are defined, parsing of a + * number larger than is representable in a double or 64 bit + * integer will result in a parse error. + * } */ typedef struct { int (* yajl_null)(void * ctx); diff --git a/src/api/yajl_tree.h b/src/api/yajl_tree.h index f23f1915..a02c5316 100644 --- a/src/api/yajl_tree.h +++ b/src/api/yajl_tree.h @@ -21,6 +21,11 @@ * * \author Florian Forster * \date August 2010 + * + * This interface makes quick parsing and extraction of + * smallish JSON docs trivial: + * + * \include example/parse_config.c */ #ifndef YAJL_TREE_H @@ -50,17 +55,18 @@ typedef enum { typedef struct yajl_val_s * yajl_val; /** - * A JSON value:is one of the seven types above. For "string", "number", - * "object", and "array" additional data is available in the "data" union. - * The "YAJL_IS_*" and "YAJL_GET_*" macros below allow type checking - * and convenient value extraction. + * A JSON value representation capable of holding one of the seven + * types above. For "string", "number", "object", and "array" + * additional data is available in the union. The "YAJL_IS_*" + * and "YAJL_GET_*" macros below allow type checking and convenient + * value extraction. */ struct yajl_val_s { /** Type of the value contained. Use the "YAJL_IS_*" macors to check for a * specific type. */ yajl_type type; - /** Type-specific data. Use the "YAJL_TO_*" macros to access these + /** Type-specific data. You may use the "YAJL_GET_*" macros to access these * members. */ union { @@ -76,7 +82,7 @@ struct yajl_val_s } number; struct { const char **keys; /*< Array of keys */ - yajl_val *values; /** Array of values. */ + yajl_val *values; /*< Array of values. */ size_t len; /*< Number of key-value-pairs. */ } object; struct { @@ -92,7 +98,7 @@ struct yajl_val_s * Parses an null-terminated string containing JSON data and returns a pointer * to the top-level value (root of the parse tree). * - * \param input Pointer to a null-terminated string containing + * \param input Pointer to a null-terminated utf8 string containing * JSON data. * \param error_buffer Pointer to a buffer in which an error message will * be stored if \em yajl_tree_parse fails, or @@ -112,9 +118,7 @@ YAJL_API yajl_val yajl_tree_parse (const char *input, char *error_buffer, size_t error_buffer_size); /** - * Free a parse tree. - * - * Recursively frees a pointer returned by "yajl_tree_parse". + * Free a parse tree returned by "yajl_tree_parse". * * \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL * is valid and results in a no-op. @@ -122,7 +126,18 @@ YAJL_API yajl_val yajl_tree_parse (const char *input, YAJL_API void yajl_tree_free (yajl_val v); /** - * Access a nested value. + * Access a nested value inside a tree. + * + * \param parent the node under which you'd like to extract values. + * \param path A null terminated array of strings, each the name of an object key + * \param type the yajl_type of the object you seek, or yajl_t_any if any will do. + * + * \returns a pointer to the found value, or NULL if we came up empty. + * + * Future Ideas: it'd be nice to move path to a string and implement support for + * a teeny tiny micro language here, so you can extract array elements, do things + * like .first and .last, even .length. Inspiration from JSONPath and css selectors? + * No it wouldn't be fast, but that's not what this API is about. */ YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type); diff --git a/src/yajl b/src/yajl index c59dd96f..a7b52054 100644 --- a/src/yajl +++ b/src/yajl @@ -1,3 +1,8 @@ +/** +\example reformatter/json_reformat.c +\example example/parse_config.c +*/ + /*! \mainpage Yet Another JSON Library (YAJL) \author Lloyd Hilaiel @@ -5,9 +10,7 @@ Yet Another JSON Library (YAJL) is a small event-driven (SAX-style) JSON parser written in ANSI C, and a small validating JSON -generator. It also includes a small simplified tree interface for -simplified parsing and extraction of data from smallish JSON documents. -YAJL is released under the permissive ISC license. +generator. YAJL is released under the permissive ISC license. \section features Features @@ -17,186 +20,15 @@ YAJL is released under the permissive ISC license. -# tiny -# event driven -# support for generating "beautified" JSON + -# includes +It also includes a small simplified tree interface for +simplified parsing and extraction of data from smallish JSON documents. \section usage Usage -The following code sample is a complete JSON "reformating" program. It -demonstrates how to perform stream parsing and generation. - -\code -#include -#include - -#include -#include -#include - -static int reformat_null(void * ctx) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_null(g); -} - -static int reformat_boolean(void * ctx, int boolean) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_bool(g, boolean); -} - -static int reformat_number(void * ctx, const char * s, size_t l) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_number(g, s, l); -} - -static int reformat_string(void * ctx, const unsigned char * stringVal, - size_t stringLen) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen); -} - -static int reformat_map_key(void * ctx, const unsigned char * stringVal, - size_t stringLen) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen); -} - -static int reformat_start_map(void * ctx) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_map_open(g); -} - - -static int reformat_end_map(void * ctx) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_map_close(g); -} - -static int reformat_start_array(void * ctx) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_array_open(g); -} - -static int reformat_end_array(void * ctx) -{ - yajl_gen g = (yajl_gen) ctx; - return yajl_gen_status_ok == yajl_gen_array_close(g); -} - -static yajl_callbacks callbacks = { - reformat_null, - reformat_boolean, - NULL, - NULL, - reformat_number, - reformat_string, - reformat_start_map, - reformat_map_key, - reformat_end_map, - reformat_start_array, - reformat_end_array -}; - -static void -usage(const char * progname) -{ - fprintf(stderr, "%s: reformat json from stdin\n" - "usage: json_reformat [options]\n" - " -m minimize json rather than beautify (default)\n" - " -u allow invalid UTF8 inside strings during parsing\n", - progname); - exit(1); - -} - -int -main(int argc, char ** argv) -{ - yajl_handle hand; - static unsigned char fileData[65536]; - /* generator config */ - yajl_gen g; - yajl_status stat; - size_t rd; - int retval = 0; - - g = yajl_gen_alloc(NULL); - yajl_gen_config(g, yajl_gen_beautify, 1); - yajl_gen_config(g, yajl_gen_validate_utf8, 1); - - /* ok. open file. let's read and parse */ - hand = yajl_alloc(&callbacks, NULL, (void *) g); - /* and let's allow comments by default */ - yajl_config(hand, yajl_allow_comments, 1); - - /* check arguments.*/ - int a = 1; - while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) { - unsigned int i; - for ( i=1; i < strlen(argv[a]); i++) { - switch (argv[a][i]) { - case 'm': - yajl_gen_config(g, yajl_gen_beautify, 0); - break; - case 'u': - yajl_config(hand, yajl_dont_validate_strings, 1); - break; - default: - fprintf(stderr, "unrecognized option: '%c'\n\n", - argv[a][i]); - usage(argv[0]); - } - } - ++a; - } - if (a < argc) { - usage(argv[0]); - } - - - for (;;) { - rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); - - if (rd == 0) { - if (!feof(stdin)) { - fprintf(stderr, "error on file read.\n"); - retval = 1; - } - break; - } - fileData[rd] = 0; - - stat = yajl_parse(hand, fileData, rd); - - if (stat != yajl_status_ok) break; - - { - const unsigned char * buf; - size_t len; - yajl_gen_get_buf(g, &buf, &len); - fwrite(buf, 1, len, stdout); - yajl_gen_clear(g); - } - } - - stat = yajl_complete_parse(hand); - - if (stat != yajl_status_ok) { - unsigned char * str = yajl_get_error(hand, 1, fileData, rd); - fprintf(stderr, "%s", (const char *) str); - yajl_free_error(hand, str); - retval = 1; - } - - yajl_gen_free(g); - yajl_free(hand); +The following code sample is a complete JSON "reformating" program. +See json_reformat.c for a complete example of stream based parsing +and generation of JSON. See parse_config.c for an example of the +simplified tree interface. - return retval; -} -\endcode */