[tracker/wip/sam/resource: 15/18] libtracker-sparql: Fix tracker-resource Turtle generation



commit 87aa14c5e403fc61c3f43ab5a6a8cc40c9fec93d
Author: Sam Thursfield <ssssam gmail com>
Date:   Sun Apr 10 22:16:55 2016 +0100

    libtracker-sparql: Fix tracker-resource Turtle generation

 src/libtracker-sparql/tracker-resource.c |  306 ++++++++++++++++++------------
 1 files changed, 180 insertions(+), 126 deletions(-)
---
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index 1b09e94..61f6400 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -559,6 +559,186 @@ tracker_resource_compare (TrackerResource *a,
 };
 
 
+/* Helper function for serialization code. This allows you to selectively
+ * populate 'interned_namespaces' from 'all_namespaces' based on when a
+ * particular prefix is actually used. This is quite inefficient compared
+ * to just dumping all known namespaces, but it makes the serializated
+ * output more readable.
+ */
+static void
+maybe_intern_prefix_of_compact_uri (TrackerNamespaceManager *all_namespaces,
+                                    TrackerNamespaceManager *interned_namespaces,
+                                    const char *uri)
+{
+       /* The TrackerResource API doesn't distinguish between compact URIs and full
+        * URIs. This is fine as long as users don't add prefixes that can be
+        * confused with URIs. Both URIs and CURIEs can have anything following
+        * the ':', so without hardcoding knowledge of well-known protocols here,
+        * we can't really tell if the user has done something dumb like defining a
+        * "urn" prefix.
+        */
+       char *prefix = g_uri_parse_scheme (uri);
+
+       if (prefix == NULL) {
+               g_warning ("Invalid URI or compact URI: %s", uri);
+               return;
+       }
+
+       if (tracker_namespace_manager_has_prefix (all_namespaces, prefix)) {
+               if (!tracker_namespace_manager_has_prefix (interned_namespaces, prefix)) {
+                       const char *namespace = tracker_namespace_manager_lookup_prefix (all_namespaces, 
prefix);
+                       tracker_namespace_manager_add_prefix (interned_namespaces, prefix, namespace);
+               }
+       }
+}
+
+
+typedef struct {
+       TrackerNamespaceManager *all_namespaces, *our_namespaces;
+       GString *string;
+       GList *done_list;
+} GenerateTurtleData;
+
+void generate_turtle (TrackerResource *resource, GenerateTurtleData *data);
+
+void
+generate_turtle_resources_foreach (gpointer key,
+                                   gpointer value_ptr,
+                                   gpointer user_data)
+{
+       const char *property = key;
+       const GValue *value = value_ptr;
+       GenerateTurtleData *data = user_data;
+
+       if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
+               TrackerResource *resource = g_value_get_object (value);
+               if (g_list_find_custom (data->done_list, resource, (GCompareFunc) tracker_resource_compare) 
== NULL) {
+                       generate_turtle (resource, data);
+                       g_string_append (data->string, "\n");
+                       data->done_list = g_list_prepend (data->done_list, resource);
+               }
+       }
+}
+
+static void
+generate_turtle_value (const GValue *value,
+                       GenerateTurtleData *data)
+{
+       GType type = G_VALUE_TYPE (value);
+       if (type == TRACKER_TYPE_URI) {
+               const char *uri = g_value_get_string (value);
+               maybe_intern_prefix_of_compact_uri (data->all_namespaces, data->our_namespaces, uri);
+               g_string_append_printf(data->string, "%s", uri);
+       } else if (type == TRACKER_TYPE_RESOURCE) {
+               TrackerResource *relation = TRACKER_RESOURCE (g_value_get_object (value));
+               g_string_append_printf(data->string, "<%s>", tracker_resource_get_identifier (relation));
+       } else if (type == G_TYPE_STRING) {
+               g_string_append_printf(data->string, "\"%s\"", g_value_get_string (value));
+       } else {
+               GValue str_value = G_VALUE_INIT;
+               g_value_init (&str_value, G_TYPE_STRING);
+               if (g_value_transform (value, &str_value)) {
+                       g_string_append (data->string, g_value_get_string (&str_value));
+               } else {
+                       g_warning ("Cannot serialize value of type %s to Turtle", G_VALUE_TYPE_NAME (value));
+               }
+               g_value_unset (&str_value);
+       }
+}
+
+void
+generate_turtle_property (const char *property,
+                          const GValue *value,
+                          GenerateTurtleData *data)
+{
+       g_string_append (data->string, property);
+       g_string_append (data->string, " ");
+       if (G_VALUE_HOLDS (value, G_TYPE_PTR_ARRAY)) {
+               int i;
+               GPtrArray *array = g_value_get_boxed (value);
+               if (array->len > 0) {
+                       generate_turtle_value (g_ptr_array_index (array, i), data);
+                       for (i = 1; i < array->len; i++) {
+                               g_string_append (data->string, " , ");
+                               generate_turtle_value (g_ptr_array_index (array, i), data);
+                       }
+               }
+       } else {
+               generate_turtle_value (value, data);
+       }
+}
+
+void
+generate_turtle (TrackerResource *resource,
+                 GenerateTurtleData *data)
+{
+       TrackerResourcePrivate *priv = GET_PRIVATE (resource);
+       GString *result;
+       GHashTableIter iter;
+       const char *property;
+       const GValue *value;
+
+       g_hash_table_foreach (priv->properties, generate_turtle_resources_foreach, data);
+
+       g_string_append_printf (data->string, "<%s> ", priv->identifier);
+
+       g_hash_table_iter_init (&iter, priv->properties);
+       if (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value))
+               while (TRUE) {
+                       generate_turtle_property (property, value, data);
+
+                       maybe_intern_prefix_of_compact_uri (data->all_namespaces, data->our_namespaces, 
property);
+
+                       if (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value)) {
+                               g_string_append (data->string, " ;\n  ");
+                       } else {
+                               g_string_append (data->string, " .\n");
+                               break;
+                       }
+               }
+}
+
+/**
+ * tracker_resource_print_turtle:
+ * @resource: a #TrackerResource
+ * @error: address where an error can be returned
+ *
+ * Serialize all the information in @resource as a Turtle document.
+ *
+ * The generated Turtle should correspond to this standard:
+ * <https://www.w3.org/TR/2014/REC-turtle-20140225/>
+ *
+ * Returns: a newly-allocated string
+ *
+ * Since: 1.10
+ */
+char *
+tracker_resource_print_turtle (TrackerResource *self,
+                               TrackerNamespaceManager *namespaces)
+{
+       GenerateTurtleData context;
+       char *prefixes;
+
+       context.all_namespaces = namespaces;
+       context.our_namespaces = tracker_namespace_manager_new ();
+       context.string = g_string_new ("");
+       context.done_list = NULL;
+
+       maybe_intern_prefix_of_compact_uri (context.all_namespaces, context.our_namespaces, 
tracker_resource_get_identifier(self));
+
+       generate_turtle (self, &context);
+
+       prefixes = tracker_namespace_manager_print_turtle (context.our_namespaces);
+       g_string_prepend (context.string, "\n");
+       g_string_prepend (context.string, prefixes);
+
+       g_object_unref (context.our_namespaces);
+       g_free (prefixes);
+
+       return g_string_free (context.string, FALSE);
+}
+
+
 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
@@ -701,132 +881,6 @@ tracker_resource_print_jsonld (TrackerResource *resource,
        return result;
 }
 
-typedef struct {
-       TrackerNamespaceManager *namespaces;
-       GString *string;
-       GList *done_list;
-} GenerateTurtleData;
-
-void generate_turtle (TrackerResource *resource, GenerateTurtleData *data);
-
-void
-generate_turtle_resources_foreach (gpointer key,
-                                   gpointer value_ptr,
-                                   gpointer user_data)
-{
-       const char *property = key;
-       const GValue *value = value_ptr;
-       GenerateTurtleData *data = user_data;
-
-       if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
-               TrackerResource *resource = g_value_get_object (value);
-               if (g_list_find_custom (data->done_list, resource, (GCompareFunc) tracker_resource_compare) 
== NULL) {
-                       generate_turtle (resource, data);
-                       g_string_append (data->string, "\n");
-                       data->done_list = g_list_prepend (data->done_list, resource);
-               }
-       }
-}
-
-static void
-append_value_to_turtle_string (const GValue *value,
-                               GString *string)
-{
-       GType type = G_VALUE_TYPE (value);
-       if (type == TRACKER_TYPE_URI) {
-               g_string_append_printf(string, "%s", g_value_get_string (value));
-       } else if (type == TRACKER_TYPE_RESOURCE) {
-               TrackerResource *relation = TRACKER_RESOURCE (g_value_get_object (value));
-               g_string_append_printf(string, "<%s>", tracker_resource_get_identifier (relation));
-       } else if (type == G_TYPE_STRING) {
-               g_string_append_printf(string, "\"%s\"", g_value_get_string (value));
-       } else {
-               GValue str_value = G_VALUE_INIT;
-               g_value_init (&str_value, G_TYPE_STRING);
-               if (g_value_transform (value, &str_value)) {
-                       g_string_append (string, g_value_get_string (&str_value));
-               } else {
-                       g_warning ("Cannot serialize value of type %s to Turtle", G_VALUE_TYPE_NAME (value));
-               }
-               g_value_unset (&str_value);
-       }
-}
-
-void
-generate_turtle_property (const char *property,
-                          const GValue *value,
-                          GenerateTurtleData *data)
-{
-       g_string_append (data->string, property);
-       g_string_append (data->string, " ");
-       if (G_VALUE_HOLDS (value, G_TYPE_PTR_ARRAY)) {
-               int i;
-               GPtrArray *array = g_value_get_boxed (value);
-               for (i = 0; i < array->len; i++) {
-                       append_value_to_turtle_string (g_ptr_array_index (array, i), data->string);
-                       g_string_append (data->string, ", ");
-               }
-       } else {
-               append_value_to_turtle_string (value, data->string);
-       }
-}
-
-void
-generate_turtle (TrackerResource *resource,
-                 GenerateTurtleData *data)
-{
-       TrackerResourcePrivate *priv = GET_PRIVATE (resource);
-       GString *result;
-       GHashTableIter iter;
-       const char *property;
-       const GValue *value;
-
-       g_hash_table_foreach (priv->properties, generate_turtle_resources_foreach, data);
-
-       g_string_append_printf (data->string, "<%s> ", priv->identifier);
-
-       g_hash_table_iter_init (&iter, priv->properties);
-       if (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value))
-               while (TRUE) {
-                       generate_turtle_property (property, value, data);
-                       if (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value)) {
-                               g_string_append (data->string, ";\n  ");
-                       } else {
-                               g_string_append (data->string, ".\n");
-                               break;
-                       }
-               }
-}
-
-/**
- * tracker_resource_print_turtle:
- * @resource: a #TrackerResource
- * @error: address where an error can be returned
- *
- * Serialize all the information in @resource as a Turtle document.
- *
- * The generated Turtle should correspond to this standard:
- * <https://www.w3.org/TR/2014/REC-turtle-20140225/>
- *
- * Returns: a newly-allocated string
- *
- * Since: 1.10
- */
-char *
-tracker_resource_print_turtle(TrackerResource *self,
-                              TrackerNamespaceManager *namespaces)
-{
-       GenerateTurtleData context;
-
-       context.namespaces = namespaces;
-       context.string = g_string_new ("");
-       context.done_list = NULL;
-
-       generate_turtle (self, &context);
-
-       return g_string_free (context.string, FALSE);
-}
-
 
 typedef struct {
        TrackerNamespaceManager *namespaces;


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