From 7e246706dd26a539ad94d79cfd26dcb9ac69ea70 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Fri, 8 Apr 2016 17:57:46 +0100 Subject: libtracker-sparql: Add TrackerNamespaceManager This will keep track of a set of namespaces and their prefixes. Then, when we are serializing a resource, we can use it. This is separate from the Namespace and Ontologies classes in libtracker-data. They may be able to make use of it though. https://bugzilla.gnome.org/show_bug.cgi?id=767472 --- src/libtracker-sparql/Makefile.am | 3 + src/libtracker-sparql/tracker-namespace-manager.c | 311 ++++++++++++++++++++++ src/libtracker-sparql/tracker-namespace-manager.h | 49 ++++ 3 files changed, 363 insertions(+) create mode 100644 src/libtracker-sparql/tracker-namespace-manager.c create mode 100644 src/libtracker-sparql/tracker-namespace-manager.h diff --git a/src/libtracker-sparql/Makefile.am b/src/libtracker-sparql/Makefile.am index 48ed4ad23..3f6925b6f 100644 --- a/src/libtracker-sparql/Makefile.am +++ b/src/libtracker-sparql/Makefile.am @@ -22,6 +22,8 @@ libtracker_sparql_la_SOURCES = \ tracker-builder.vala \ tracker-connection.vala \ tracker-cursor.vala \ + tracker-namespace-manager.c \ + tracker-namespace-manager.h \ tracker-utils.vala \ tracker-uri.c \ tracker-ontologies.h \ @@ -48,6 +50,7 @@ tracker-sparql-$(TRACKER_API_VERSION).vapi: tracker-sparql.vapi libtracker_sparqlinclude_HEADERS = \ $(vala_header) \ + tracker-namespace-manager.h \ tracker-ontologies.h \ tracker-sparql.h \ tracker-version.h diff --git a/src/libtracker-sparql/tracker-namespace-manager.c b/src/libtracker-sparql/tracker-namespace-manager.c new file mode 100644 index 000000000..a3b3974d0 --- /dev/null +++ b/src/libtracker-sparql/tracker-namespace-manager.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2016, Sam Thursfield + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include + +#include + +#include "tracker-namespace-manager.h" +#include "tracker-ontologies.h" + +#define MAX_PREFIX_LENGTH 100 + +struct _TrackerNamespaceManager { + GObject parent; +}; + +typedef struct { + GHashTable *prefix_to_namespace; + GHashTable *namespace_to_prefix; +} TrackerNamespaceManagerPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (TrackerNamespaceManager, tracker_namespace_manager, G_TYPE_OBJECT); +#define GET_PRIVATE(object) (tracker_namespace_manager_get_instance_private (object)) + +/** + * SECTION: tracker-namespace-manager + * @short_description: A set of well-known namespaces, and known abbreviations for them + * @title: TrackerNamespaceManager + * @stability: Stable + * @include: tracker-namespace-manager.h + * + * + * #TrackerNamespaceManager keeps track of namespaces. It allows you to assign + * short prefixes for them to avoid typing full URLs all the time. + * + * The syntax used is that of Compact URIs (CURIEs) as defined here: + * + * + * Usually you'll want to use the default namespace manager, as returned by + * tracker_namespace_manager_get_default(). This has a set of well-known + * prefixes predefined. + * + */ + +static void finalize (GObject *object); + +static void +tracker_namespace_manager_class_init (TrackerNamespaceManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = finalize; +} + +static void +tracker_namespace_manager_init (TrackerNamespaceManager *self) +{ + TrackerNamespaceManagerPrivate *priv = GET_PRIVATE (self); + + priv->prefix_to_namespace = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->namespace_to_prefix = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +static void +finalize (GObject *object) +{ + TrackerNamespaceManagerPrivate *priv; + + priv = GET_PRIVATE (TRACKER_NAMESPACE_MANAGER (object)); + + g_hash_table_unref (priv->prefix_to_namespace); + g_hash_table_unref (priv->namespace_to_prefix); + + (G_OBJECT_CLASS (tracker_namespace_manager_parent_class)->finalize) (object); +} + +/** + * tracker_namespace_manager_new: + * + * Creates a new #TrackerNamespaceManager instance. + * + * Returns: a new #TrackerNamespaceManager instance + * + * Since: 1.10 + */ +TrackerNamespaceManager * +tracker_namespace_manager_new () +{ + TrackerNamespaceManager *namespace_manager; + + namespace_manager = g_object_new (TRACKER_TYPE_NAMESPACE_MANAGER, NULL); + + return namespace_manager; +} + +/** + * tracker_namespace_manager_get_default: + * + * Returns the global #TrackerNamespaceManager that contains a set of well-known + * namespaces and prefixes, such as rdf:, rdfs:, nie:, tracker:, etc. + * + * Note that the list of prefixes and namespaces is hardcoded in + * libtracker-sparql. It may not correspond with the installed set of + * ontologies, if they have been modified since they were installed. + * + * Returns: a global, shared #TrackerNamespaceManager instance + * + * Since: 1.10 + */ +TrackerNamespaceManager * +tracker_namespace_manager_get_default () +{ + static TrackerNamespaceManager * volatile default_namespace_manager__volatile = NULL; + + if (g_once_init_enter (&default_namespace_manager__volatile)) { + TrackerNamespaceManager *manager = tracker_namespace_manager_new(); + + tracker_namespace_manager_add_prefix (manager, "rdf", TRACKER_PREFIX_RDF); + tracker_namespace_manager_add_prefix (manager, "rdfs", TRACKER_PREFIX_RDFS); + tracker_namespace_manager_add_prefix (manager, "xsd", TRACKER_PREFIX_XSD); + tracker_namespace_manager_add_prefix (manager, "tracker", TRACKER_PREFIX_TRACKER); + tracker_namespace_manager_add_prefix (manager, "dc", TRACKER_PREFIX_DC); + + tracker_namespace_manager_add_prefix (manager, "nrl", TRACKER_PREFIX_NRL); + tracker_namespace_manager_add_prefix (manager, "nmo", TRACKER_PREFIX_NMO); + tracker_namespace_manager_add_prefix (manager, "nie", TRACKER_PREFIX_NIE); + tracker_namespace_manager_add_prefix (manager, "nco", TRACKER_PREFIX_NCO); + tracker_namespace_manager_add_prefix (manager, "nao", TRACKER_PREFIX_NAO); + tracker_namespace_manager_add_prefix (manager, "nid3", TRACKER_PREFIX_NID3); + tracker_namespace_manager_add_prefix (manager, "nfo", TRACKER_PREFIX_NFO); + + tracker_namespace_manager_add_prefix (manager, "slo", TRACKER_PREFIX_SLO); + tracker_namespace_manager_add_prefix (manager, "nmm", TRACKER_PREFIX_NMM); + tracker_namespace_manager_add_prefix (manager, "mlo", TRACKER_PREFIX_MLO); + tracker_namespace_manager_add_prefix (manager, "mfo", TRACKER_PREFIX_MFO); + + g_once_init_leave (&default_namespace_manager__volatile, manager); + } + + return default_namespace_manager__volatile; +} + +/** + * tracker_namespace_manager_has_prefix: + * @self: a #TrackerNamespaceManager + * @prefix: a string + * + * Returns: %TRUE if the #TrackerNamespaceManager knows about @prefix, %FALSE otherwise + * + * Since: 1.10 + */ +gboolean +tracker_namespace_manager_has_prefix (TrackerNamespaceManager *self, + const char *prefix) +{ + TrackerNamespaceManagerPrivate *priv = GET_PRIVATE (self); + + return g_hash_table_contains (priv->prefix_to_namespace, prefix); +} + +/** + * tracker_namespace_manager_lookup_prefix: + * @self: a #TrackerNamespaceManager + * @prefix: a string + * + * Looks up the namespace URI corresponding to @prefix, or %NULL if the prefix + * is not known. + * + * Returns: a string owned by the #TrackerNamespaceManager, or %NULL + * + * Since: 1.10 + */ +const char * +tracker_namespace_manager_lookup_prefix (TrackerNamespaceManager *self, + const char *prefix) +{ + TrackerNamespaceManagerPrivate *priv = GET_PRIVATE (self); + + return g_hash_table_lookup (priv->prefix_to_namespace, prefix); +} + +/** + * tracker_namespace_manager_add_prefix: + * @self: a #TrackerNamespaceManager + * @prefix: a short, unique prefix to identify @namespace + * @namespace: the URL of the given namespace + * + * Adds @prefix as the recognised abbreviaton of @namespace. + * + * Only one prefix is allowed for a given namespace, and all prefixes must + * be unique. + * + * Since: 1.10 + */ +void +tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self, + const char *prefix, + const char *namespace) +{ + TrackerNamespaceManagerPrivate *priv; + const char *str; + + priv = GET_PRIVATE (TRACKER_NAMESPACE_MANAGER (self)); + + if (strlen (prefix) > MAX_PREFIX_LENGTH) { + g_error ("Prefix is too long: max %i characters.", MAX_PREFIX_LENGTH); + return; + } + + str = g_hash_table_lookup (priv->prefix_to_namespace, prefix); + if (str) { + g_error ("Prefix %s already points to %s", prefix, str); + return; + } + + str = g_hash_table_lookup (priv->namespace_to_prefix, namespace); + if (str) { + g_error ("Namespace %s already has prefix %s", namespace, str); + return; + } + + g_hash_table_insert (priv->prefix_to_namespace, g_strdup (prefix), g_strdup (namespace)); + g_hash_table_insert (priv->namespace_to_prefix, g_strdup (namespace), g_strdup (prefix)); +} + +/** + * tracker_namespace_manager_expand_uri: + * @self: a #TrackerNamespaceManager + * @compact_uri: a URI or compact URI + * + * If @compact_uri begins with one of the prefixes known to this + * #TrackerNamespaceManager, then the return value will be the + * expanded URI. Otherwise, a copy of @compact_uri will be returned. + * + * Returns: a newly-allocated string + * + * Since: 1.10 + */ +char * +tracker_namespace_manager_expand_uri (TrackerNamespaceManager *self, + const char *compact_uri) +{ + TrackerNamespaceManagerPrivate *priv = GET_PRIVATE (self); + + char prefix[MAX_PREFIX_LENGTH + 1] = { 0 }; + char *colon; + char *namespace = NULL; + + colon = strchr (compact_uri, ':'); + if (colon != NULL) { + int colon_pos = colon - compact_uri; + if (colon_pos < MAX_PREFIX_LENGTH) { + strncpy (prefix, compact_uri, colon_pos - 1); + prefix[colon_pos] = 0; + + namespace = g_hash_table_lookup (priv->prefix_to_namespace, prefix); + } + } + + if (namespace) { + return g_strconcat (namespace, colon, NULL); + } else { + return g_strdup (compact_uri); + } +} + +/** + * tracker_namespace_manager_print_turtle: + * @self: a #TrackerNamespaceManager + * + * Writes out all namespaces as Turtle @prefix statements. + * + * Returns: a newly-allocated string + * + * Since: 1.10 + */ +char * +tracker_namespace_manager_print_turtle (TrackerNamespaceManager *self) +{ + TrackerNamespaceManagerPrivate *priv = GET_PRIVATE (self); + GString *result = g_string_new (""); + GHashTableIter iter; + const char *prefix; + const char *namespace; + + g_hash_table_iter_init (&iter, priv->prefix_to_namespace); + while (g_hash_table_iter_next (&iter, (gpointer *)&prefix, (gpointer *)&namespace)) { + g_string_append_printf (result, "@prefix %s: <%s> .\n", prefix, namespace); + } + + return g_string_free (result, FALSE); +} diff --git a/src/libtracker-sparql/tracker-namespace-manager.h b/src/libtracker-sparql/tracker-namespace-manager.h new file mode 100644 index 000000000..2a6e45e9d --- /dev/null +++ b/src/libtracker-sparql/tracker-namespace-manager.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016, Sam Thursfield + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __LIBTRACKER_SPARQL_NAMESPACE_MANAGER_H__ +#define __LIBTRACKER_SPARQL_NAMESPACE_MANAGER_H__ + +#include + +G_BEGIN_DECLS + +#if !defined (__LIBTRACKER_SPARQL_INSIDE__) && !defined (TRACKER_COMPILATION) +#error "only must be included directly." +#endif + +#define TRACKER_TYPE_NAMESPACE_MANAGER (tracker_namespace_manager_get_type()) +G_DECLARE_FINAL_TYPE (TrackerNamespaceManager, tracker_namespace_manager, TRACKER, NAMESPACE_MANAGER, GObject) + +TrackerNamespaceManager *tracker_namespace_manager_new (void); +TrackerNamespaceManager *tracker_namespace_manager_get_default (void); + +char *tracker_namespace_manager_expand_uri (TrackerNamespaceManager *self, const char *compact_uri); + +gboolean tracker_namespace_manager_has_prefix (TrackerNamespaceManager *self, const char *prefix); +const char *tracker_namespace_manager_lookup_prefix (TrackerNamespaceManager *self, const char *prefix); + +void tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self, const char *prefix, const char *namespace); + +char *tracker_namespace_manager_print_turtle (TrackerNamespaceManager *self); + +G_END_DECLS + +#endif /* __LIBTRACKER_SPARQL_NAMESPACE_MANAGER_H__ */ + -- cgit v1.2.1