[tracker/wip/sam/resource: 15/17] libtracker-sparql: Add JSON-LD serialisation to TrackerResource



commit a2920b6a8803bb42317b39511798b69dae8c95a6
Author: Sam Thursfield <sam afuera me uk>
Date:   Thu Apr 7 18:03:00 2016 +0100

    libtracker-sparql: Add JSON-LD serialisation to TrackerResource

 src/libtracker-sparql/tracker-resource.c |  148 ++++++++++++++++++++++++++----
 src/libtracker-sparql/tracker-resource.h |    2 +
 2 files changed, 133 insertions(+), 17 deletions(-)
---
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index c0cc206..e3148a2 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -18,6 +18,7 @@
  */
 
 #include <glib.h>
+#include <json-glib/json-glib.h>
 
 #include <string.h>
 
@@ -503,22 +504,137 @@ tracker_resource_identifier_compare_func (TrackerResource *resource,
        return strcmp (priv->identifier, identifier);
 }
 
-GString *
-tracker_resource_print_jsonld_string (TrackerResource *resource)
+
+static void generate_jsonld_foreach (gpointer key, gpointer value_ptr, gpointer user_data);
+
+/* FIXME: this could hit an infinite loop if there are circular resource
+ * relationships, make sure those are tested & detected.
+ */
+/* This is not exposed publically right now because then everything including
+ * tracker-resource.h would need to pull in the json-glib dependency ...
+ */
+static JsonNode *
+tracker_resource_generate_jsonld (TrackerResource *self,
+                                   GError **error)
+{
+       /* FIXME: generate a JSON-LD context ! */
+
+       TrackerResourcePrivate *priv = GET_PRIVATE (self);
+       JsonBuilder *builder;
+       JsonNode *result;
+
+       builder = json_builder_new ();
+       json_builder_begin_object (builder);
+
+       /* The JSON-LD spec says it is "important that nodes have an identifier", but
+        * doesn't mandate one. I think it's better to omit the ID for blank nodes
+        * (where the caller passed NULL as an identifier) than to emit something
+        * SPARQL-specific like '_:123'.
+        */
+       if (strncmp (priv->identifier, "_:", 2) != 0) {
+               json_builder_set_member_name (builder, "@id");
+               json_builder_add_string_value (builder, priv->identifier);
+       }
+
+       g_hash_table_foreach (priv->properties, generate_jsonld_foreach, builder);
+
+       json_builder_end_object (builder);
+
+       result = json_builder_get_root (builder);
+       g_object_unref (builder);
+       return result;
+};
+
+static void
+generate_jsonld_foreach (gpointer key,
+                         gpointer value_ptr,
+                         gpointer user_data)
 {
-       GString *string;
-
-       string = g_string_new ("");
-
-       /* How will this work then? */
-       /* Ignore formatting for now */
-       /*{
-               @context: {
-                       "foo": "prefix"
-               },
-               "nie:title": title
-       }*/
-       return string;
+       const char *property = key;
+       const GValue *value = value_ptr;
+       JsonBuilder *builder = JSON_BUILDER (user_data);
+       JsonNode *node;
+
+       /* FIXME: shouldn't hardcode the unexpanded prefix here!!! */
+       if (strcmp (property, "rdf:type") == 0) {
+               property = "@type";
+       }
+
+       if (G_VALUE_HOLDS (value, G_TYPE_PTR_ARRAY)) {
+               g_warning ("Not serializing property %s: arrays not yet implemented.", property);
+       } else if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
+               TrackerResource *resource;
+               GError *error = NULL;
+
+               resource = TRACKER_RESOURCE (g_value_get_object (value));
+               node = tracker_resource_generate_jsonld (resource, &error);
+
+               if (node) {
+                       json_builder_set_member_name (builder, property);
+                       json_builder_add_value (builder, node);
+               } else {
+                       g_warning ("Unable to serialize value of %s: %s", property, error->message);
+                       g_error_free (error);
+               }
+       } else if (G_VALUE_HOLDS (value, TRACKER_TYPE_URI)) {
+               /* URIs can be treated the same as strings in JSON-LD provided the @context
+                * sets the type of that property correctly. However, json_node_set_value()
+                * will reject a GValue holding TRACKER_TYPE_URI, so we have to extract the
+                * string manually here.
+                */
+               const char *uri = g_value_get_string (value);
+               node = json_node_new (JSON_NODE_VALUE);
+               json_node_set_string (node, uri);
+               json_builder_set_member_name (builder, property);
+               json_builder_add_value (builder, node);
+       } else {
+               node = json_node_new (JSON_NODE_VALUE);
+               json_node_set_value (node, value);
+               json_builder_set_member_name (builder, property);
+               json_builder_add_value (builder, node);
+       }
+}
+
+/**
+ * tracker_resource_print_jsonld:
+ * @resource: a #TrackerResource
+ * @error: address where an error can be returned
+ *
+ * Serialize all the information in @resource as a JSON-LD document.
+ *
+ * See <http://www.jsonld.org/> for more information on the JSON-LD
+ * serialization format.
+ *
+ * Returns: a newly-allocated string
+ *
+ * Since: 1.10
+ */
+char *
+tracker_resource_print_jsonld (TrackerResource *resource,
+                               GError **error)
+{
+       GError *sub_error = NULL;
+       JsonNode *json_root_node;
+       JsonGenerator *generator;
+       char *result;
+
+       json_root_node = tracker_resource_generate_jsonld (resource, &sub_error);
+
+       if (json_root_node == NULL) {
+               g_propagate_error (error, sub_error);
+               return NULL;
+       }
+
+       generator = json_generator_new ();
+       json_generator_set_root (generator, json_root_node);
+       json_generator_set_pretty (generator, TRUE);
+
+       result = json_generator_to_data (generator, NULL);
+
+       json_node_free (json_root_node);
+       g_object_unref (generator);
+
+       return result;
 }
 
 typedef struct {
@@ -730,5 +846,3 @@ tracker_resource_generate_sparql_update (TrackerResource *resource,
        }
        tracker_sparql_builder_insert_close (builder);
 }
-
-/* FIXME: serialize_json should be generate_json for consistency with this */
diff --git a/src/libtracker-sparql/tracker-resource.h b/src/libtracker-sparql/tracker-resource.h
index 7ced0bd..e6daff9 100644
--- a/src/libtracker-sparql/tracker-resource.h
+++ b/src/libtracker-sparql/tracker-resource.h
@@ -64,6 +64,8 @@ const char *tracker_resource_get_first_uri (TrackerResource *self, const char *p
 const char *tracker_resource_get_identifier (TrackerResource *self);
 gint tracker_resource_identifier_compare_func (TrackerResource *resource, const char *identifier);
 
+char *tracker_resource_print_jsonld (TrackerResource *self, GError **error);
+
 void tracker_resource_generate_sparql_update (TrackerResource *self, TrackerSparqlBuilder *builder, const 
char *graph_id, GError **error);
 
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]