Blame json-glib/json-path.c

Packit 4c4d6b
/* json-path.h - JSONPath implementation
Packit 4c4d6b
 *
Packit 4c4d6b
 * This file is part of JSON-GLib
Packit 4c4d6b
 * Copyright © 2011  Intel Corp.
Packit 4c4d6b
 *
Packit 4c4d6b
 * This library is free software; you can redistribute it and/or
Packit 4c4d6b
 * modify it under the terms of the GNU Lesser General Public
Packit 4c4d6b
 * License as published by the Free Software Foundation; either
Packit 4c4d6b
 * version 2.1 of the License, or (at your option) any later version.
Packit 4c4d6b
 *
Packit 4c4d6b
 * This library is distributed in the hope that it will be useful,
Packit 4c4d6b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4c4d6b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4c4d6b
 * Lesser General Public License for more details.
Packit 4c4d6b
 *
Packit 4c4d6b
 * You should have received a copy of the GNU Lesser General Public
Packit 4c4d6b
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit 4c4d6b
 *
Packit 4c4d6b
 * Author:
Packit 4c4d6b
 *   Emmanuele Bassi  <ebassi@linux.intel.com>
Packit 4c4d6b
 */
Packit 4c4d6b
Packit 4c4d6b
/**
Packit 4c4d6b
 * SECTION:json-path
Packit 4c4d6b
 * @Title: JsonPath
Packit 4c4d6b
 * @short_description: JSONPath implementation
Packit 4c4d6b
 *
Packit 4c4d6b
 * #JsonPath is a simple class implementing the JSONPath syntax for extracting
Packit 4c4d6b
 * data out of a JSON tree. While the semantics of the JSONPath expressions are
Packit 4c4d6b
 * heavily borrowed by the XPath specification for XML, the syntax follows the
Packit 4c4d6b
 * ECMAScript origins of JSON.
Packit 4c4d6b
 *
Packit 4c4d6b
 * Once a #JsonPath instance has been created, it has to compile a JSONPath
Packit 4c4d6b
 * expression using json_path_compile() before being able to match it to a
Packit 4c4d6b
 * JSON tree; the same #JsonPath instance can be used to match multiple JSON
Packit 4c4d6b
 * trees. It it also possible to compile a new JSONPath expression using the
Packit 4c4d6b
 * same #JsonPath instance; the previous expression will be discarded only if
Packit 4c4d6b
 * the compilation of the new expression is successful.
Packit 4c4d6b
 *
Packit 4c4d6b
 * The simple convenience function json_path_query() can be used for one-off
Packit 4c4d6b
 * matching.
Packit 4c4d6b
 *
Packit 4c4d6b
 * ## Syntax of the JSONPath expressions ##
Packit 4c4d6b
 *
Packit 4c4d6b
 * A JSONPath expression is composed by path indices and operators.
Packit 4c4d6b
 * Each path index can either be a member name or an element index inside
Packit 4c4d6b
 * a JSON tree. A JSONPath expression must start with the '$' operator; each
Packit 4c4d6b
 * path index is separated using either the dot notation or the bracket
Packit 4c4d6b
 * notation, e.g.:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   // dot notation
Packit 4c4d6b
 *   $.store.book[0].title
Packit 4c4d6b
 *
Packit 4c4d6b
 *   // bracket notation
Packit 4c4d6b
 *   $['store']['book'][0]['title']
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * The available operators are:
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Root node
Packit 4c4d6b
 *   The `$` character represents the root node of the JSON tree, and
Packit 4c4d6b
 *   matches the entire document.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Child nodes can either be matched using `.` or `[]`. For instance,
Packit 4c4d6b
 *   both `$.store.book` and `$['store']['book']` match the contents of
Packit 4c4d6b
 *   the book member of the store object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Child nodes can be reached without specifying the whole tree structure
Packit 4c4d6b
 *   through the recursive descent operator, or `..`. For instance,
Packit 4c4d6b
 *   `$..author` matches all author member in every object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Child nodes can grouped through the wildcard operator, or `*`. For
Packit 4c4d6b
 *   instance, `$.store.book[*].author` matches all author members of any
Packit 4c4d6b
 *   object element contained in the book array of the store object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Element nodes can be accessed using their index (starting from zero)
Packit 4c4d6b
 *   in the subscript operator `[]`. For instance, `$.store.book[0]` matches
Packit 4c4d6b
 *   the first element of the book array of the store object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Subsets of element nodes can be accessed using the set notation
Packit 4c4d6b
 *   operator `[i,j,...]`. For instance, `$.store.book[0,2]` matches the
Packit 4c4d6b
 *   elements 0 and 2 (the first and third) of the book array of the store
Packit 4c4d6b
 *   object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * * Slices of element nodes can be accessed using the slice notation
Packit 4c4d6b
 *   operation `[start:end:step]`. If start is omitted, the starting index
Packit 4c4d6b
 *   of the slice is implied to be zero; if end is omitted, the ending index
Packit 4c4d6b
 *   of the slice is implied to be the length of the array; if step is
Packit 4c4d6b
 *   omitted, the step of the slice is implied to be 1. For instance,
Packit 4c4d6b
 *   `$.store.book[:2]` matches the first two elements of the book array
Packit 4c4d6b
 *   of the store object.
Packit 4c4d6b
 *
Packit 4c4d6b
 * More information about JSONPath is available on Stefan Gössner's
Packit 4c4d6b
 * [JSONPath website](http://goessner.net/articles/JsonPath/).
Packit 4c4d6b
 *
Packit 4c4d6b
 * ## Example of JSONPath matches
Packit 4c4d6b
 * The following example shows some of the results of using #JsonPath
Packit 4c4d6b
 * on a JSON tree. We use the following JSON description of a bookstore:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   { "store": {
Packit 4c4d6b
 *       "book": [
Packit 4c4d6b
 *         { "category": "reference", "author": "Nigel Rees",
Packit 4c4d6b
 *           "title": "Sayings of the Century", "price": "8.95"  },
Packit 4c4d6b
 *         { "category": "fiction", "author": "Evelyn Waugh",
Packit 4c4d6b
 *           "title": "Sword of Honour", "price": "12.99" },
Packit 4c4d6b
 *         { "category": "fiction", "author": "Herman Melville",
Packit 4c4d6b
 *           "title": "Moby Dick", "isbn": "0-553-21311-3",
Packit 4c4d6b
 *           "price": "8.99" },
Packit 4c4d6b
 *         { "category": "fiction", "author": "J. R. R. Tolkien",
Packit 4c4d6b
 *           "title": "The Lord of the Rings", "isbn": "0-395-19395-8",
Packit 4c4d6b
 *           "price": "22.99" }
Packit 4c4d6b
 *       ],
Packit 4c4d6b
 *       "bicycle": { "color": "red", "price": "19.95" }
Packit 4c4d6b
 *     }
Packit 4c4d6b
 *   }
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * We can parse the JSON using #JsonParser:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   JsonParser *parser = json_parser_new ();
Packit 4c4d6b
 *   json_parser_load_from_data (parser, json_data, -1, NULL);
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * If we run the following code:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   JsonNode *result;
Packit 4c4d6b
 *   JsonPath *path = json_path_new ();
Packit 4c4d6b
 *   json_path_compile (path, "$.store..author", NULL);
Packit 4c4d6b
 *   result = json_path_match (path, json_parser_get_root (parser));
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * The result #JsonNode will contain an array with all values of the
Packit 4c4d6b
 * author member of the objects in the JSON tree. If we use a
Packit 4c4d6b
 * #JsonGenerator to convert the #JsonNode to a string and print it:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   JsonGenerator *generator = json_generator_new ();
Packit 4c4d6b
 *   json_generator_set_root (generator, result);
Packit 4c4d6b
 *   char *str = json_generator_to_data (generator, NULL);
Packit 4c4d6b
 *   g_print ("Results: %s\n", str);
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * The output will be:
Packit 4c4d6b
 *
Packit 4c4d6b
 * |[
Packit 4c4d6b
 *   ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
Packit 4c4d6b
 * ]|
Packit 4c4d6b
 *
Packit 4c4d6b
 * #JsonPath is available since JSON-GLib 0.14
Packit 4c4d6b
 */
Packit 4c4d6b
Packit 4c4d6b
#include "config.h"
Packit 4c4d6b
Packit 4c4d6b
#include <string.h>
Packit 4c4d6b
Packit 4c4d6b
#include <glib/gi18n-lib.h>
Packit 4c4d6b
Packit 4c4d6b
#include "json-path.h"
Packit 4c4d6b
Packit 4c4d6b
#include "json-debug.h"
Packit 4c4d6b
#include "json-types-private.h"
Packit 4c4d6b
Packit 4c4d6b
typedef enum {
Packit 4c4d6b
  JSON_PATH_NODE_ROOT,
Packit 4c4d6b
  JSON_PATH_NODE_CHILD_MEMBER,
Packit 4c4d6b
  JSON_PATH_NODE_CHILD_ELEMENT,
Packit 4c4d6b
  JSON_PATH_NODE_RECURSIVE_DESCENT,
Packit 4c4d6b
  JSON_PATH_NODE_WILDCARD_MEMBER,
Packit 4c4d6b
  JSON_PATH_NODE_WILDCARD_ELEMENT,
Packit 4c4d6b
  JSON_PATH_NODE_ELEMENT_SET,
Packit 4c4d6b
  JSON_PATH_NODE_ELEMENT_SLICE
Packit 4c4d6b
} PathNodeType;
Packit 4c4d6b
Packit 4c4d6b
typedef struct _PathNode        PathNode;
Packit 4c4d6b
Packit 4c4d6b
struct _JsonPath
Packit 4c4d6b
{
Packit 4c4d6b
  GObject parent_instance;
Packit 4c4d6b
Packit 4c4d6b
  /* the compiled path */
Packit 4c4d6b
  GList *nodes;
Packit 4c4d6b
Packit 4c4d6b
  guint is_compiled : 1;
Packit 4c4d6b
};
Packit 4c4d6b
Packit 4c4d6b
struct _JsonPathClass
Packit 4c4d6b
{
Packit 4c4d6b
  GObjectClass parent_class;
Packit 4c4d6b
};
Packit 4c4d6b
Packit 4c4d6b
struct _PathNode
Packit 4c4d6b
{
Packit 4c4d6b
  PathNodeType node_type;
Packit 4c4d6b
Packit 4c4d6b
  union {
Packit 4c4d6b
    /* JSON_PATH_NODE_CHILD_ELEMENT */
Packit 4c4d6b
    int element_index;
Packit 4c4d6b
Packit 4c4d6b
    /* JSON_PATH_NODE_CHILD_MEMBER */
Packit 4c4d6b
    char *member_name;
Packit 4c4d6b
Packit 4c4d6b
    /* JSON_PATH_NODE_ELEMENT_SET */
Packit 4c4d6b
    struct { int n_indices; int *indices; } set;
Packit 4c4d6b
Packit 4c4d6b
    /* JSON_PATH_NODE_ELEMENT_SLICE */
Packit 4c4d6b
    struct { int start, end, step; } slice;
Packit 4c4d6b
  } data;
Packit 4c4d6b
};
Packit 4c4d6b
Packit 4c4d6b
G_DEFINE_QUARK (json-path-error-quark, json_path_error)
Packit 4c4d6b
Packit 4c4d6b
G_DEFINE_TYPE (JsonPath, json_path, G_TYPE_OBJECT)
Packit 4c4d6b
Packit 4c4d6b
static void
Packit 4c4d6b
path_node_free (gpointer data)
Packit 4c4d6b
{
Packit 4c4d6b
  if (data != NULL)
Packit 4c4d6b
    {
Packit 4c4d6b
      PathNode *node = data;
Packit 4c4d6b
Packit 4c4d6b
      switch (node->node_type)
Packit 4c4d6b
        {
Packit 4c4d6b
        case JSON_PATH_NODE_CHILD_MEMBER:
Packit 4c4d6b
          g_free (node->data.member_name);
Packit 4c4d6b
          break;
Packit 4c4d6b
Packit 4c4d6b
        case JSON_PATH_NODE_ELEMENT_SET:
Packit 4c4d6b
          g_free (node->data.set.indices);
Packit 4c4d6b
          break;
Packit 4c4d6b
Packit 4c4d6b
        default:
Packit 4c4d6b
          break;
Packit 4c4d6b
        }
Packit 4c4d6b
Packit 4c4d6b
      g_free (node);
Packit 4c4d6b
    }
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
static void
Packit 4c4d6b
json_path_finalize (GObject *gobject)
Packit 4c4d6b
{
Packit 4c4d6b
  JsonPath *self = JSON_PATH (gobject);
Packit 4c4d6b
Packit 4c4d6b
  g_list_free_full (self->nodes, path_node_free);
Packit 4c4d6b
Packit 4c4d6b
  G_OBJECT_CLASS (json_path_parent_class)->finalize (gobject);
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
static void
Packit 4c4d6b
json_path_class_init (JsonPathClass *klass)
Packit 4c4d6b
{
Packit 4c4d6b
  G_OBJECT_CLASS (klass)->finalize = json_path_finalize;
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
static void
Packit 4c4d6b
json_path_init (JsonPath *self)
Packit 4c4d6b
{
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
/**
Packit 4c4d6b
 * json_path_new:
Packit 4c4d6b
 *
Packit 4c4d6b
 * Creates a new #JsonPath instance.
Packit 4c4d6b
 *
Packit 4c4d6b
 * Once created, the #JsonPath object should be used with json_path_compile()
Packit 4c4d6b
 * and json_path_match().
Packit 4c4d6b
 *
Packit 4c4d6b
 * Return value: (transfer full): the newly created #JsonPath instance. Use
Packit 4c4d6b
 *   g_object_unref() to free the allocated resources when done
Packit 4c4d6b
 *
Packit 4c4d6b
 * Since: 0.14
Packit 4c4d6b
 */
Packit 4c4d6b
JsonPath *
Packit 4c4d6b
json_path_new (void)
Packit 4c4d6b
{
Packit 4c4d6b
  return g_object_new (JSON_TYPE_PATH, NULL);
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
#ifdef JSON_ENABLE_DEBUG
Packit 4c4d6b
/* used as the function for a g_list_foreach() on a list of PathNode; needs
Packit 4c4d6b
 * a GString as the payload to build the output string
Packit 4c4d6b
 */
Packit 4c4d6b
static void
Packit 4c4d6b
json_path_foreach_print (gpointer data,
Packit 4c4d6b
                         gpointer user_data)
Packit 4c4d6b
{
Packit 4c4d6b
  PathNode *cur_node = data;
Packit 4c4d6b
  GString *buf = user_data;
Packit 4c4d6b
Packit 4c4d6b
  switch (cur_node->node_type)
Packit 4c4d6b
    {
Packit 4c4d6b
    case JSON_PATH_NODE_ROOT:
Packit 4c4d6b
      g_string_append (buf, "
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_CHILD_MEMBER:
Packit 4c4d6b
      g_string_append_printf (buf, "<member '%s'", cur_node->data.member_name);
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_CHILD_ELEMENT:
Packit 4c4d6b
      g_string_append_printf (buf, "<element '%d'", cur_node->data.element_index);
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_RECURSIVE_DESCENT:
Packit 4c4d6b
      g_string_append (buf, "
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_WILDCARD_MEMBER:
Packit 4c4d6b
      g_string_append (buf, "
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_WILDCARD_ELEMENT:
Packit 4c4d6b
      g_string_append (buf, "
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_ELEMENT_SET:
Packit 4c4d6b
      {
Packit 4c4d6b
        int i;
Packit 4c4d6b
Packit 4c4d6b
        g_string_append (buf, "
Packit 4c4d6b
        for (i = 0; i < cur_node->data.set.n_indices - 1; i++)
Packit 4c4d6b
          g_string_append_printf (buf, "'%d', ", cur_node->data.set.indices[i]);
Packit 4c4d6b
Packit 4c4d6b
        g_string_append_printf (buf, "'%d'", cur_node->data.set.indices[i]);
Packit 4c4d6b
      }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_ELEMENT_SLICE:
Packit 4c4d6b
      g_string_append_printf (buf, "
Packit 4c4d6b
                              cur_node->data.slice.start,
Packit 4c4d6b
                              cur_node->data.slice.end,
Packit 4c4d6b
                              cur_node->data.slice.step);
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    default:
Packit 4c4d6b
      g_string_append (buf, "
Packit 4c4d6b
      break;
Packit 4c4d6b
    }
Packit 4c4d6b
Packit 4c4d6b
  g_string_append (buf, ">");
Packit 4c4d6b
}
Packit 4c4d6b
#endif /* JSON_ENABLE_DEBUG */
Packit 4c4d6b
Packit 4c4d6b
/**
Packit 4c4d6b
 * json_path_compile:
Packit 4c4d6b
 * @path: a #JsonPath
Packit 4c4d6b
 * @expression: a JSONPath expression
Packit 4c4d6b
 * @error: return location for a #GError, or %NULL
Packit 4c4d6b
 *
Packit 4c4d6b
 * Validates and decomposes @expression.
Packit 4c4d6b
 *
Packit 4c4d6b
 * A JSONPath expression must be compiled before calling json_path_match().
Packit 4c4d6b
 *
Packit 4c4d6b
 * Return value: %TRUE on success; on error, @error will be set with
Packit 4c4d6b
 *   the %JSON_PATH_ERROR domain and a code from the #JsonPathError
Packit 4c4d6b
 *   enumeration, and %FALSE will be returned
Packit 4c4d6b
 *
Packit 4c4d6b
 * Since: 0.14
Packit 4c4d6b
 */
Packit 4c4d6b
gboolean
Packit 4c4d6b
json_path_compile (JsonPath    *path,
Packit 4c4d6b
                   const char  *expression,
Packit 4c4d6b
                   GError     **error)
Packit 4c4d6b
{
Packit 4c4d6b
  const char *p, *end_p;
Packit 4c4d6b
  PathNode *root = NULL;
Packit 4c4d6b
  GList *nodes = NULL;
Packit 4c4d6b
Packit 4c4d6b
  g_return_val_if_fail (expression != NULL, FALSE);
Packit 4c4d6b
Packit 4c4d6b
  p = expression;
Packit 4c4d6b
Packit 4c4d6b
  while (*p != '\0')
Packit 4c4d6b
    {
Packit 4c4d6b
      switch (*p)
Packit 4c4d6b
        {
Packit 4c4d6b
        case '$':
Packit 4c4d6b
          {
Packit 4c4d6b
            PathNode *node;
Packit 4c4d6b
Packit 4c4d6b
            if (root != NULL)
Packit 4c4d6b
              {
Packit 4c4d6b
                g_set_error_literal (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                     JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                     _("Only one root node is allowed in a JSONPath expression"));
Packit 4c4d6b
                return FALSE;
Packit 4c4d6b
              }
Packit 4c4d6b
Packit 4c4d6b
            if (!(*(p + 1) == '.' || *(p + 1) == '[' || *(p + 1) == '\0'))
Packit 4c4d6b
              {
Packit 4c4d6b
                g_set_error (error, JSON_PATH_ERROR,
Packit 4c4d6b
                             JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                             /* translators: the %c is the invalid character */
Packit 4c4d6b
                             _("Root node followed by invalid character “%c”"),
Packit 4c4d6b
                             *(p + 1));
Packit 4c4d6b
                return FALSE;
Packit 4c4d6b
              }
Packit 4c4d6b
            
Packit 4c4d6b
            node = g_new0 (PathNode, 1);
Packit 4c4d6b
            node->node_type = JSON_PATH_NODE_ROOT;
Packit 4c4d6b
Packit 4c4d6b
            root = node;
Packit 4c4d6b
            nodes = g_list_prepend (NULL, root);
Packit 4c4d6b
          }
Packit 4c4d6b
          break;
Packit 4c4d6b
Packit 4c4d6b
        case '.':
Packit 4c4d6b
        case '[':
Packit 4c4d6b
          {
Packit 4c4d6b
            PathNode *node = NULL;
Packit 4c4d6b
Packit 4c4d6b
            if (*p == '.' && *(p + 1) == '.')
Packit 4c4d6b
              {
Packit 4c4d6b
                node = g_new0 (PathNode, 1);
Packit 4c4d6b
                node->node_type = JSON_PATH_NODE_RECURSIVE_DESCENT;
Packit 4c4d6b
              }
Packit 4c4d6b
            else if (*p == '.' && *(p + 1) == '*')
Packit 4c4d6b
              {
Packit 4c4d6b
                node = g_new0 (PathNode, 1);
Packit 4c4d6b
                node->node_type = JSON_PATH_NODE_WILDCARD_MEMBER;
Packit 4c4d6b
Packit 4c4d6b
                p += 1;
Packit 4c4d6b
              }
Packit 4c4d6b
            else if (*p == '.')
Packit 4c4d6b
              {
Packit 4c4d6b
                end_p = p + 1;
Packit 4c4d6b
                while (!(*end_p == '.' || *end_p == '[' || *end_p == '\0'))
Packit 4c4d6b
                  end_p += 1;
Packit 4c4d6b
Packit 4c4d6b
                if (end_p == p + 1)
Packit 4c4d6b
                  {
Packit 4c4d6b
                    g_set_error_literal (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                         JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                         _("Missing member name or wildcard after . character"));
Packit 4c4d6b
                    goto fail;
Packit 4c4d6b
                  }
Packit 4c4d6b
Packit 4c4d6b
                node = g_new0 (PathNode, 1);
Packit 4c4d6b
                node->node_type = JSON_PATH_NODE_CHILD_MEMBER;
Packit 4c4d6b
                node->data.member_name = g_strndup (p + 1, end_p - p - 1);
Packit 4c4d6b
Packit 4c4d6b
                p = end_p - 1;
Packit 4c4d6b
              }
Packit 4c4d6b
            else if (*p == '[' && *(p + 1) == '\'')
Packit 4c4d6b
              {
Packit 4c4d6b
                if (*(p + 2) == '*' && *(p + 3) == '\'' && *(p + 4) == ']')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_WILDCARD_MEMBER;
Packit 4c4d6b
Packit 4c4d6b
                    p += 4;
Packit 4c4d6b
                  }
Packit 4c4d6b
                else
Packit 4c4d6b
                  {
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_CHILD_MEMBER;
Packit 4c4d6b
Packit 4c4d6b
                    end_p = strchr (p + 2, '\'');
Packit 4c4d6b
                    node->data.member_name = g_strndup (p + 2, end_p - p - 2);
Packit 4c4d6b
Packit 4c4d6b
                    p = end_p + 1;
Packit 4c4d6b
                  }
Packit 4c4d6b
              }
Packit 4c4d6b
            else if (*p == '[' && *(p + 1) == '*' && *(p + 2) == ']')
Packit 4c4d6b
              {
Packit 4c4d6b
                node = g_new0 (PathNode, 1);
Packit 4c4d6b
                node->node_type = JSON_PATH_NODE_WILDCARD_ELEMENT;
Packit 4c4d6b
Packit 4c4d6b
                p += 1;
Packit 4c4d6b
              }
Packit 4c4d6b
            else if (*p == '[')
Packit 4c4d6b
              {
Packit 4c4d6b
                int sign = 1;
Packit 4c4d6b
                int idx;
Packit 4c4d6b
Packit 4c4d6b
                end_p = p + 1;
Packit 4c4d6b
Packit 4c4d6b
                if (*end_p == '-')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    sign = -1;
Packit 4c4d6b
                    end_p += 1;
Packit 4c4d6b
                  }
Packit 4c4d6b
Packit 4c4d6b
                /* slice with missing start */
Packit 4c4d6b
                if (*end_p == ':')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    int slice_end = g_ascii_strtoll (end_p + 1, (char **) &end_p, 10) * sign;
Packit 4c4d6b
                    int slice_step = 1;
Packit 4c4d6b
Packit 4c4d6b
                    if (*end_p == ':')
Packit 4c4d6b
                      {
Packit 4c4d6b
                        end_p += 1;
Packit 4c4d6b
Packit 4c4d6b
                        if (*end_p == '-')
Packit 4c4d6b
                          {
Packit 4c4d6b
                            sign = -1;
Packit 4c4d6b
                            end_p += 1;
Packit 4c4d6b
                          }
Packit 4c4d6b
                        else
Packit 4c4d6b
                          sign = 1;
Packit 4c4d6b
Packit 4c4d6b
                        slice_step = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
Packit 4c4d6b
Packit 4c4d6b
                        if (*end_p != ']')
Packit 4c4d6b
                          {
Packit 4c4d6b
                            g_set_error (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                         JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                         _("Malformed slice expression “%*s”"),
Packit 4c4d6b
                                         (int)(end_p - p),
Packit 4c4d6b
                                         p + 1);
Packit 4c4d6b
                            goto fail;
Packit 4c4d6b
                          }
Packit 4c4d6b
                      }
Packit 4c4d6b
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_ELEMENT_SLICE;
Packit 4c4d6b
                    node->data.slice.start = 0;
Packit 4c4d6b
                    node->data.slice.end = slice_end;
Packit 4c4d6b
                    node->data.slice.step = slice_step;
Packit 4c4d6b
Packit 4c4d6b
                    nodes = g_list_prepend (nodes, node);
Packit 4c4d6b
                    p = end_p;
Packit 4c4d6b
                    break;
Packit 4c4d6b
                  }
Packit 4c4d6b
Packit 4c4d6b
                idx = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
Packit 4c4d6b
Packit 4c4d6b
                if (*end_p == ',')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    GArray *indices = g_array_new (FALSE, TRUE, sizeof (int));
Packit 4c4d6b
Packit 4c4d6b
                    g_array_append_val (indices, idx);
Packit 4c4d6b
Packit 4c4d6b
                    while (*end_p != ']')
Packit 4c4d6b
                      {
Packit 4c4d6b
                        end_p += 1;
Packit 4c4d6b
Packit 4c4d6b
                        if (*end_p == '-')
Packit 4c4d6b
                          {
Packit 4c4d6b
                            sign = -1;
Packit 4c4d6b
                            end_p += 1;
Packit 4c4d6b
                          }
Packit 4c4d6b
                        else
Packit 4c4d6b
                          sign = 1;
Packit 4c4d6b
Packit 4c4d6b
                        idx = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
Packit 4c4d6b
                        if (!(*end_p == ',' || *end_p == ']'))
Packit 4c4d6b
                          {
Packit 4c4d6b
                            g_array_unref (indices);
Packit 4c4d6b
                            g_set_error (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                         JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                         _("Invalid set definition “%*s”"),
Packit 4c4d6b
                                         (int)(end_p - p),
Packit 4c4d6b
                                         p + 1);
Packit 4c4d6b
                            goto fail;
Packit 4c4d6b
                          }
Packit 4c4d6b
Packit 4c4d6b
                        g_array_append_val (indices, idx);
Packit 4c4d6b
                      }
Packit 4c4d6b
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_ELEMENT_SET;
Packit 4c4d6b
                    node->data.set.n_indices =  indices->len;
Packit 4c4d6b
                    node->data.set.indices = (int *) g_array_free (indices, FALSE);
Packit 4c4d6b
                    nodes = g_list_prepend (nodes, node);
Packit 4c4d6b
                    p = end_p;
Packit 4c4d6b
                    break;
Packit 4c4d6b
                  }
Packit 4c4d6b
                else if (*end_p == ':')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    int slice_start = idx;
Packit 4c4d6b
                    int slice_end = 0;
Packit 4c4d6b
                    int slice_step = 1;
Packit 4c4d6b
Packit 4c4d6b
                    end_p += 1;
Packit 4c4d6b
Packit 4c4d6b
                    if (*end_p == '-')
Packit 4c4d6b
                      {
Packit 4c4d6b
                        sign = -1;
Packit 4c4d6b
                        end_p += 1;
Packit 4c4d6b
                      }
Packit 4c4d6b
                    else
Packit 4c4d6b
                      sign = 1;
Packit 4c4d6b
Packit 4c4d6b
                    slice_end = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
Packit 4c4d6b
                    if (*end_p == ':')
Packit 4c4d6b
                      {
Packit 4c4d6b
                        end_p += 1;
Packit 4c4d6b
Packit 4c4d6b
                        if (*end_p == '-')
Packit 4c4d6b
                          {
Packit 4c4d6b
                            sign = -1;
Packit 4c4d6b
                            end_p += 1;
Packit 4c4d6b
                          }
Packit 4c4d6b
                        else
Packit 4c4d6b
                          sign = 1;
Packit 4c4d6b
Packit 4c4d6b
                        slice_step = g_ascii_strtoll (end_p + 1, (char **) &end_p, 10) * sign;
Packit 4c4d6b
                      }
Packit 4c4d6b
Packit 4c4d6b
                    if (*end_p != ']')
Packit 4c4d6b
                      {
Packit 4c4d6b
                        g_set_error (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                     JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                     _("Invalid slice definition “%*s”"),
Packit 4c4d6b
                                     (int)(end_p - p),
Packit 4c4d6b
                                     p + 1);
Packit 4c4d6b
                        goto fail;
Packit 4c4d6b
                      }
Packit 4c4d6b
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_ELEMENT_SLICE;
Packit 4c4d6b
                    node->data.slice.start = slice_start;
Packit 4c4d6b
                    node->data.slice.end = slice_end;
Packit 4c4d6b
                    node->data.slice.step = slice_step;
Packit 4c4d6b
                    nodes = g_list_prepend (nodes, node);
Packit 4c4d6b
                    p = end_p;
Packit 4c4d6b
                    break;
Packit 4c4d6b
                  }
Packit 4c4d6b
                else if (*end_p == ']')
Packit 4c4d6b
                  {
Packit 4c4d6b
                    node = g_new0 (PathNode, 1);
Packit 4c4d6b
                    node->node_type = JSON_PATH_NODE_CHILD_ELEMENT;
Packit 4c4d6b
                    node->data.element_index = idx;
Packit 4c4d6b
                    nodes = g_list_prepend (nodes, node);
Packit 4c4d6b
                    p = end_p;
Packit 4c4d6b
                    break;
Packit 4c4d6b
                  }
Packit 4c4d6b
                else
Packit 4c4d6b
                  {
Packit 4c4d6b
                    g_set_error (error, JSON_PATH_ERROR,
Packit 4c4d6b
                                 JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                                 _("Invalid array index definition “%*s”"),
Packit 4c4d6b
                                 (int)(end_p - p),
Packit 4c4d6b
                                 p + 1);
Packit 4c4d6b
                    goto fail;
Packit 4c4d6b
                  }
Packit 4c4d6b
              }
Packit 4c4d6b
            else
Packit 4c4d6b
              break;
Packit 4c4d6b
Packit 4c4d6b
            if (node != NULL)
Packit 4c4d6b
              nodes = g_list_prepend (nodes, node);
Packit 4c4d6b
          }
Packit 4c4d6b
          break;
Packit 4c4d6b
Packit 4c4d6b
        default:
Packit 4c4d6b
          if (nodes == NULL)
Packit 4c4d6b
            {
Packit 4c4d6b
              g_set_error(error, JSON_PATH_ERROR,
Packit 4c4d6b
                          JSON_PATH_ERROR_INVALID_QUERY,
Packit 4c4d6b
                          _("Invalid first character “%c”"),
Packit 4c4d6b
                          *p);
Packit 4c4d6b
              return FALSE;
Packit 4c4d6b
            }
Packit 4c4d6b
          break;
Packit 4c4d6b
        }
Packit 4c4d6b
Packit 4c4d6b
      p += 1;
Packit 4c4d6b
    }
Packit 4c4d6b
Packit 4c4d6b
  nodes = g_list_reverse (nodes);
Packit 4c4d6b
Packit 4c4d6b
#ifdef JSON_ENABLE_DEBUG
Packit 4c4d6b
  if (JSON_HAS_DEBUG (PATH))
Packit 4c4d6b
    {
Packit 4c4d6b
      GString *buf = g_string_new (NULL);
Packit 4c4d6b
Packit 4c4d6b
      g_list_foreach (nodes, json_path_foreach_print, buf);
Packit 4c4d6b
Packit 4c4d6b
      g_message ("[PATH] " G_STRLOC ": expression '%s' => '%s'", expression, buf->str);
Packit 4c4d6b
      g_string_free (buf, TRUE);
Packit 4c4d6b
    }
Packit 4c4d6b
#endif /* JSON_ENABLE_DEBUG */
Packit 4c4d6b
Packit 4c4d6b
  g_list_free_full (path->nodes, path_node_free);
Packit 4c4d6b
Packit 4c4d6b
  path->nodes = nodes;
Packit 4c4d6b
  path->is_compiled = (path->nodes != NULL);
Packit 4c4d6b
Packit 4c4d6b
  return path->nodes != NULL;
Packit 4c4d6b
Packit 4c4d6b
fail:
Packit 4c4d6b
  g_list_free_full (nodes, path_node_free);
Packit 4c4d6b
Packit 4c4d6b
  return FALSE;
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
static void
Packit 4c4d6b
walk_path_node (GList      *path,
Packit 4c4d6b
                JsonNode   *root,
Packit 4c4d6b
                JsonArray  *results)
Packit 4c4d6b
{
Packit 4c4d6b
  PathNode *node = path->data;
Packit 4c4d6b
Packit 4c4d6b
  switch (node->node_type)
Packit 4c4d6b
    {
Packit 4c4d6b
    case JSON_PATH_NODE_ROOT:
Packit 4c4d6b
      if (path->next != NULL)
Packit 4c4d6b
          walk_path_node (path->next, root, results);
Packit 4c4d6b
      else
Packit 4c4d6b
          json_array_add_element (results, json_node_copy (root));
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_CHILD_MEMBER:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_OBJECT (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonObject *object = json_node_get_object (root);
Packit 4c4d6b
Packit 4c4d6b
          if (json_object_has_member (object, node->data.member_name))
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonNode *member = json_object_get_member (object, node->data.member_name);
Packit 4c4d6b
              
Packit 4c4d6b
              if (path->next == NULL)
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "end of path at member '%s'", node->data.member_name);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (member));
Packit 4c4d6b
                }
Packit 4c4d6b
              else
Packit 4c4d6b
                walk_path_node (path->next, member, results);
Packit 4c4d6b
            }
Packit 4c4d6b
        }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_CHILD_ELEMENT:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_ARRAY (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonArray *array = json_node_get_array (root);
Packit 4c4d6b
Packit 4c4d6b
          if (json_array_get_length (array) >= node->data.element_index)
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonNode *element = json_array_get_element (array, node->data.element_index);
Packit 4c4d6b
Packit 4c4d6b
              if (path->next == NULL)
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "end of path at element '%d'", node->data.element_index);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (element));
Packit 4c4d6b
                }
Packit 4c4d6b
              else
Packit 4c4d6b
                walk_path_node (path->next, element, results);
Packit 4c4d6b
            }
Packit 4c4d6b
        }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_RECURSIVE_DESCENT:
Packit 4c4d6b
      {
Packit 4c4d6b
        PathNode *tmp = path->next->data;
Packit 4c4d6b
Packit 4c4d6b
        switch (json_node_get_node_type (root))
Packit 4c4d6b
          {
Packit 4c4d6b
          case JSON_NODE_OBJECT:
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonObject *object = json_node_get_object (root);
Packit 4c4d6b
              GQueue *members = json_object_get_members_internal (object);
Packit 4c4d6b
              GList *l;
Packit 4c4d6b
Packit 4c4d6b
              for (l = members->head; l != NULL; l = l->next)
Packit 4c4d6b
                {
Packit 4c4d6b
                  JsonNode *m = json_object_get_member (object, l->data);
Packit 4c4d6b
Packit 4c4d6b
                  if (tmp->node_type == JSON_PATH_NODE_CHILD_MEMBER &&
Packit 4c4d6b
                      strcmp (tmp->data.member_name, l->data) == 0)
Packit 4c4d6b
                    {
Packit 4c4d6b
                      JSON_NOTE (PATH, "entering '%s'", tmp->data.member_name);
Packit 4c4d6b
                      walk_path_node (path->next, root, results);
Packit 4c4d6b
                    }
Packit 4c4d6b
                  else
Packit 4c4d6b
                    {
Packit 4c4d6b
                      JSON_NOTE (PATH, "recursing into '%s'", (char *) l->data);
Packit 4c4d6b
                      walk_path_node (path, m, results);
Packit 4c4d6b
                    }
Packit 4c4d6b
                }
Packit 4c4d6b
            }
Packit 4c4d6b
            break;
Packit 4c4d6b
Packit 4c4d6b
          case JSON_NODE_ARRAY:
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonArray *array = json_node_get_array (root);
Packit 4c4d6b
              GList *members, *l;
Packit 4c4d6b
              int i;
Packit 4c4d6b
Packit 4c4d6b
              members = json_array_get_elements (array);
Packit 4c4d6b
              for (l = members, i = 0; l != NULL; l = l->next, i += 1)
Packit 4c4d6b
                {
Packit 4c4d6b
                  JsonNode *m = l->data;
Packit 4c4d6b
Packit 4c4d6b
                  if (tmp->node_type == JSON_PATH_NODE_CHILD_ELEMENT &&
Packit 4c4d6b
                      tmp->data.element_index == i)
Packit 4c4d6b
                    {
Packit 4c4d6b
                      JSON_NOTE (PATH, "entering '%d'", tmp->data.element_index);
Packit 4c4d6b
                      walk_path_node (path->next, root, results);
Packit 4c4d6b
                    }
Packit 4c4d6b
                  else
Packit 4c4d6b
                    {
Packit 4c4d6b
                      JSON_NOTE (PATH, "recursing into '%d'", i);
Packit 4c4d6b
                      walk_path_node (path, m, results);
Packit 4c4d6b
                    }
Packit 4c4d6b
                }
Packit 4c4d6b
              g_list_free (members);
Packit 4c4d6b
            }
Packit 4c4d6b
            break;
Packit 4c4d6b
Packit 4c4d6b
          default:
Packit 4c4d6b
            break;
Packit 4c4d6b
          }
Packit 4c4d6b
      }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_WILDCARD_MEMBER:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_OBJECT (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonObject *object = json_node_get_object (root);
Packit 4c4d6b
          GQueue *members = json_object_get_members_internal (object);
Packit 4c4d6b
          GList *l;
Packit 4c4d6b
Packit 4c4d6b
          for (l = members->head; l != NULL; l = l->next)
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonNode *member = json_object_get_member (object, l->data);
Packit 4c4d6b
Packit 4c4d6b
              if (path->next != NULL)
Packit 4c4d6b
                walk_path_node (path->next, member, results);
Packit 4c4d6b
              else
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "glob match member '%s'", (char *) l->data);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (member));
Packit 4c4d6b
                }
Packit 4c4d6b
            }
Packit 4c4d6b
        }
Packit 4c4d6b
      else
Packit 4c4d6b
        json_array_add_element (results, json_node_copy (root));
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_WILDCARD_ELEMENT:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_ARRAY (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonArray *array = json_node_get_array (root);
Packit 4c4d6b
          GList *elements, *l;
Packit 4c4d6b
          int i;
Packit 4c4d6b
Packit 4c4d6b
          elements = json_array_get_elements (array);
Packit 4c4d6b
          for (l = elements, i = 0; l != NULL; l = l->next, i += 1)
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonNode *element = l->data;
Packit 4c4d6b
Packit 4c4d6b
              if (path->next != NULL)
Packit 4c4d6b
                walk_path_node (path->next, element, results);
Packit 4c4d6b
              else
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "glob match element '%d'", i);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (element));
Packit 4c4d6b
                }
Packit 4c4d6b
            }
Packit 4c4d6b
          g_list_free (elements);
Packit 4c4d6b
        }
Packit 4c4d6b
      else
Packit 4c4d6b
        json_array_add_element (results, json_node_copy (root));
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_ELEMENT_SET:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_ARRAY (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonArray *array = json_node_get_array (root);
Packit 4c4d6b
          int i;
Packit 4c4d6b
Packit 4c4d6b
          for (i = 0; i < node->data.set.n_indices; i += 1)
Packit 4c4d6b
            {
Packit 4c4d6b
              int idx = node->data.set.indices[i];
Packit 4c4d6b
              JsonNode *element = json_array_get_element (array, idx);
Packit 4c4d6b
Packit 4c4d6b
              if (path->next != NULL)
Packit 4c4d6b
                walk_path_node (path->next, element, results);
Packit 4c4d6b
              else
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "set element '%d'", idx);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (element));
Packit 4c4d6b
                }
Packit 4c4d6b
            }
Packit 4c4d6b
        }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    case JSON_PATH_NODE_ELEMENT_SLICE:
Packit 4c4d6b
      if (JSON_NODE_HOLDS_ARRAY (root))
Packit 4c4d6b
        {
Packit 4c4d6b
          JsonArray *array = json_node_get_array (root);
Packit 4c4d6b
          int i, start, end;
Packit 4c4d6b
Packit 4c4d6b
          if (node->data.slice.start < 0)
Packit 4c4d6b
            {
Packit 4c4d6b
              start = json_array_get_length (array)
Packit 4c4d6b
                    + node->data.slice.start;
Packit 4c4d6b
Packit 4c4d6b
              end = json_array_get_length (array)
Packit 4c4d6b
                  + node->data.slice.end;
Packit 4c4d6b
            }
Packit 4c4d6b
          else
Packit 4c4d6b
            {
Packit 4c4d6b
              start = node->data.slice.start;
Packit 4c4d6b
              end = node->data.slice.end;
Packit 4c4d6b
            }
Packit 4c4d6b
Packit 4c4d6b
          for (i = start; i < end; i += node->data.slice.step)
Packit 4c4d6b
            {
Packit 4c4d6b
              JsonNode *element = json_array_get_element (array, i);
Packit 4c4d6b
Packit 4c4d6b
              if (path->next != NULL)
Packit 4c4d6b
                walk_path_node (path->next, element, results);
Packit 4c4d6b
              else
Packit 4c4d6b
                {
Packit 4c4d6b
                  JSON_NOTE (PATH, "slice element '%d'", i);
Packit 4c4d6b
                  json_array_add_element (results, json_node_copy (element));
Packit 4c4d6b
                }
Packit 4c4d6b
            }
Packit 4c4d6b
        }
Packit 4c4d6b
      break;
Packit 4c4d6b
Packit 4c4d6b
    default:
Packit 4c4d6b
      break;
Packit 4c4d6b
    }
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
/**
Packit 4c4d6b
 * json_path_match:
Packit 4c4d6b
 * @path: a compiled #JsonPath
Packit 4c4d6b
 * @root: a #JsonNode
Packit 4c4d6b
 *
Packit 4c4d6b
 * Matches the JSON tree pointed by @root using the expression compiled
Packit 4c4d6b
 * into the #JsonPath.
Packit 4c4d6b
 *
Packit 4c4d6b
 * The matching #JsonNodes will be copied into a #JsonArray and
Packit 4c4d6b
 * returned wrapped in a #JsonNode.
Packit 4c4d6b
 *
Packit 4c4d6b
 * Return value: (transfer full): a newly-created #JsonNode of type
Packit 4c4d6b
 *   %JSON_NODE_ARRAY containing an array of matching #JsonNodes.
Packit 4c4d6b
 *   Use json_node_unref() when done
Packit 4c4d6b
 *
Packit 4c4d6b
 * Since: 0.14
Packit 4c4d6b
 */
Packit 4c4d6b
JsonNode *
Packit 4c4d6b
json_path_match (JsonPath *path,
Packit 4c4d6b
                 JsonNode *root)
Packit 4c4d6b
{
Packit 4c4d6b
  JsonArray *results;
Packit 4c4d6b
  JsonNode *retval;
Packit 4c4d6b
Packit 4c4d6b
  g_return_val_if_fail (JSON_IS_PATH (path), NULL);
Packit 4c4d6b
  g_return_val_if_fail (path->is_compiled, NULL);
Packit 4c4d6b
  g_return_val_if_fail (root != NULL, NULL);
Packit 4c4d6b
Packit 4c4d6b
  results = json_array_new ();
Packit 4c4d6b
Packit 4c4d6b
  walk_path_node (path->nodes, root, results);
Packit 4c4d6b
Packit 4c4d6b
  retval = json_node_new (JSON_NODE_ARRAY);
Packit 4c4d6b
  json_node_take_array (retval, results);
Packit 4c4d6b
Packit 4c4d6b
  return retval;
Packit 4c4d6b
}
Packit 4c4d6b
Packit 4c4d6b
/**
Packit 4c4d6b
 * json_path_query:
Packit 4c4d6b
 * @expression: a JSONPath expression
Packit 4c4d6b
 * @root: the root of a JSON tree
Packit 4c4d6b
 * @error: return location for a #GError, or %NULL
Packit 4c4d6b
 *
Packit 4c4d6b
 * Queries a JSON tree using a JSONPath expression.
Packit 4c4d6b
 *
Packit 4c4d6b
 * This function is a simple wrapper around json_path_new(),
Packit 4c4d6b
 * json_path_compile() and json_path_match(). It implicitly
Packit 4c4d6b
 * creates a #JsonPath instance, compiles @expression and
Packit 4c4d6b
 * matches it against the JSON tree pointed by @root.
Packit 4c4d6b
 *
Packit 4c4d6b
 * Return value: (transfer full): a newly-created #JsonNode of type
Packit 4c4d6b
 *   %JSON_NODE_ARRAY containing an array of matching #JsonNodes.
Packit 4c4d6b
 *   Use json_node_unref() when done
Packit 4c4d6b
 *
Packit 4c4d6b
 * Since: 0.14
Packit 4c4d6b
 */
Packit 4c4d6b
JsonNode *
Packit 4c4d6b
json_path_query (const char  *expression,
Packit 4c4d6b
                 JsonNode    *root,
Packit 4c4d6b
                 GError     **error)
Packit 4c4d6b
{
Packit 4c4d6b
  JsonPath *path = json_path_new ();
Packit 4c4d6b
  JsonNode *retval;
Packit 4c4d6b
Packit 4c4d6b
  if (!json_path_compile (path, expression, error))
Packit 4c4d6b
    {
Packit 4c4d6b
      g_object_unref (path);
Packit 4c4d6b
      return NULL;
Packit 4c4d6b
    }
Packit 4c4d6b
Packit 4c4d6b
  retval = json_path_match (path, root);
Packit 4c4d6b
Packit 4c4d6b
  g_object_unref (path);
Packit 4c4d6b
Packit 4c4d6b
  return retval;
Packit 4c4d6b
}