From 261d05a4cdcc1f64824615cdc81b4b467d0a5f57 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sat, 10 Nov 2007 02:15:44 +0000 Subject: Add support for parsing assignments Some JSON web APIs return a full JavaScript assignment instead of just the data structure (and I'm looking at you, Tumblr). This is done in clear violation of the grammar published in the RFC 4627, and it's evidently done because most web developers are too lazy for doing a var foo = eval('(' + text ')'); and want everything defined for them. JsonParser will blissfully ignore the left-hand part of the assignment but, in the interest of the developer who cares, will record: 1. that the parsed statement was in fact an assignment and 2. the name of the variable used. The function json_parser_has_assignment() can be used to query both the presence of an assignment and the variable name at the same time. --- json-glib/json-parser.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) (limited to 'json-glib/json-parser.c') diff --git a/json-glib/json-parser.c b/json-glib/json-parser.c index 4b89db1..5df7999 100644 --- a/json-glib/json-parser.c +++ b/json-glib/json-parser.c @@ -51,6 +51,9 @@ struct _JsonParserPrivate GScanner *scanner; GError *last_error; + + guint has_assignment : 1; + gchar *variable_name; }; static const GScannerConfig json_scanner_config = @@ -95,7 +98,8 @@ static const GScannerConfig json_scanner_config = static const gchar symbol_names[] = "true\0" "false\0" - "null\0"; + "null\0" + "var\0"; static const struct { @@ -104,7 +108,8 @@ static const struct } symbols[] = { { 0, JSON_TOKEN_TRUE }, { 5, JSON_TOKEN_FALSE }, - { 11, JSON_TOKEN_NULL } + { 11, JSON_TOKEN_NULL }, + { 16, JSON_TOKEN_VAR } }; static const guint n_symbols = G_N_ELEMENTS (symbols); @@ -152,6 +157,8 @@ json_parser_dispose (GObject *gobject) priv->last_error = NULL; } + g_free (priv->variable_name); + G_OBJECT_CLASS (json_parser_parent_class)->dispose (gobject); } @@ -326,6 +333,9 @@ json_parser_init (JsonParser *parser) priv->root = NULL; priv->current_node = NULL; + + priv->has_assignment = FALSE; + priv->variable_name = NULL; } static guint @@ -735,6 +745,38 @@ json_parse_statement (JsonParser *parser, priv->root = priv->current_node = json_node_new (JSON_NODE_ARRAY); return json_parse_array (parser, scanner, FALSE); + /* some web APIs are not only passing the data structures: they are + * also passing an assigment, which makes parsing horribly complicated + * only because web developers are lazy, and writing "var foo = " is + * evidently too much to request from them. + */ + case JSON_TOKEN_VAR: + { + guint next_token; + gchar *name; + + /* swallow the 'var' token... */ + token = g_scanner_get_next_token (scanner); + + /* ... swallow the variable name... */ + next_token = g_scanner_get_next_token (scanner); + if (next_token != G_TOKEN_IDENTIFIER) + return G_TOKEN_IDENTIFIER; + + name = g_strdup (scanner->value.v_identifier); + + /* ... and finally swallow the '=' */ + next_token = g_scanner_get_next_token (scanner); + if (next_token != '=') + return '='; + + priv->has_assignment = TRUE; + priv->variable_name = name; + + return json_parse_statement (parser, scanner); + } + break; + case JSON_TOKEN_NULL: priv->root = priv->current_node = json_node_new (JSON_NODE_NULL); return G_TOKEN_NONE; @@ -1074,3 +1116,37 @@ json_parser_get_current_pos (JsonParser *parser) return 0; } + +/** + * json_parser_has_assignment: + * @parser: a #JsonParser + * @variable_name: return location for the variable name, or %NULL + * + * A JSON data stream might sometimes contain an assignment, even though + * it would technically constitute a violation of the RFC. #JsonParser + * will ignore the left hand identifier and parse the right hand value + * of the assignment. It will record, though, the existence of the + * assignment in the data stream and the variable name used. + * + * Return value: %TRUE if there was an assignment, %FALSE otherwise. If + * @variable_name is not %NULL it will be set to the name of the variable + * used in the assignment. The string is owned by #JsonParser and should + * never be modified or freed. + * + * Since: 0.4 + */ +gboolean +json_parser_has_assignment (JsonParser *parser, + gchar **variable_name) +{ + JsonParserPrivate *priv; + + g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE); + + priv = parser->priv; + + if (priv->has_assignment && variable_name) + *variable_name = priv->variable_name; + + return priv->has_assignment; +} -- cgit v1.2.1