diff options
author | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-10 02:15:44 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@openedhand.com> | 2007-11-10 02:15:44 +0000 |
commit | 261d05a4cdcc1f64824615cdc81b4b467d0a5f57 (patch) | |
tree | 7c4392c3d1845787bc853b819550e45e0fa3219a /json-glib/json-parser.c | |
parent | 4eade1089355ebcf0614d0cfbc9c441513b7d97a (diff) | |
download | json-glib-261d05a4cdcc1f64824615cdc81b4b467d0a5f57.tar.gz |
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.
Diffstat (limited to 'json-glib/json-parser.c')
-rw-r--r-- | json-glib/json-parser.c | 80 |
1 files changed, 78 insertions, 2 deletions
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; +} |