summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-12-12 15:55:47 +0100
committerCarlos Garnacho <carlosg@gnome.org>2020-12-13 20:51:54 +0100
commitc454bb8af370fa7a629547a79c1a7440452de872 (patch)
tree6bb87c5127d7ad4c1dbf62c62fdc3e15d1a66f1d
parent3fc59161f48f2f2fbd038089febb4e0a32a95e35 (diff)
downloadtracker-c454bb8af370fa7a629547a79c1a7440452de872.tar.gz
libtracker-sparql: Add private XML serializer task
This object takes care of serializing cursors into application/sparql-results+xml format.
-rw-r--r--docs/reference/libtracker-sparql/meson.build1
-rw-r--r--src/libtracker-sparql/meson.build3
-rw-r--r--src/libtracker-sparql/tracker-serializer-xml.c260
-rw-r--r--src/libtracker-sparql/tracker-serializer-xml.h36
4 files changed, 299 insertions, 1 deletions
diff --git a/docs/reference/libtracker-sparql/meson.build b/docs/reference/libtracker-sparql/meson.build
index d5817657c..cc9c793a9 100644
--- a/docs/reference/libtracker-sparql/meson.build
+++ b/docs/reference/libtracker-sparql/meson.build
@@ -39,6 +39,7 @@ private_headers = [
'tracker-private.h',
'tracker-serializer.h',
'tracker-serializer-json.h',
+ 'tracker-serializer-xml.h',
'direct',
'bus',
'remote',
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
index 55248ac38..0e6064e67 100644
--- a/src/libtracker-sparql/meson.build
+++ b/src/libtracker-sparql/meson.build
@@ -27,6 +27,7 @@ libtracker_sparql_c_sources = files(
'tracker-statement.c',
'tracker-serializer.c',
'tracker-serializer-json.c',
+ 'tracker-serializer-xml.c',
'tracker-uri.c',
'tracker-utils.c',
'tracker-version.c',
@@ -51,7 +52,7 @@ libtracker_sparql_c_public_headers = files(
libtracker_sparql_intermediate = static_library('tracker-sparql-intermediate',
enum_types,
libtracker_sparql_c_sources,
- dependencies: [tracker_common_dep, json_glib],
+ dependencies: [tracker_common_dep, json_glib, libxml2],
gnu_symbol_visibility: 'hidden',
)
diff --git a/src/libtracker-sparql/tracker-serializer-xml.c b/src/libtracker-sparql/tracker-serializer-xml.c
new file mode 100644
index 000000000..a28d48c32
--- /dev/null
+++ b/src/libtracker-sparql/tracker-serializer-xml.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * 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.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+/* Serialization of cursors to the XML format defined at:
+ * https://www.w3.org/TR/2013/REC-rdf-sparql-XMLres-20130321/
+ */
+
+#include "config.h"
+
+#include "tracker-serializer-xml.h"
+
+#include <libxml/xmlwriter.h>
+
+struct _TrackerSerializerXml
+{
+ TrackerSerializer parent_instance;
+ xmlBufferPtr buffer;
+ xmlTextWriterPtr writer;
+ GPtrArray *vars;
+ gssize current_pos;
+
+ guint stream_closed : 1;
+ guint cursor_started : 1;
+ guint cursor_finished : 1;
+ guint head_printed : 1;
+};
+
+G_DEFINE_TYPE (TrackerSerializerXml, tracker_serializer_xml,
+ TRACKER_TYPE_SERIALIZER)
+
+static void
+tracker_serializer_xml_finalize (GObject *object)
+{
+ g_input_stream_close (G_INPUT_STREAM (object), NULL, NULL);
+
+ G_OBJECT_CLASS (tracker_serializer_xml_parent_class)->finalize (object);
+}
+
+static gboolean
+serialize_up_to_position (TrackerSerializerXml *serializer_xml,
+ gsize pos,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSparqlCursor *cursor;
+ GError *inner_error = NULL;
+ gint i;
+
+ if (!serializer_xml->buffer)
+ serializer_xml->buffer = xmlBufferCreate ();
+ if (!serializer_xml->writer)
+ serializer_xml->writer = xmlNewTextWriterMemory (serializer_xml->buffer, 0);
+ if (!serializer_xml->vars)
+ serializer_xml->vars = g_ptr_array_new_with_free_func (g_free);
+
+ cursor = tracker_serializer_get_cursor (TRACKER_SERIALIZER (serializer_xml));
+
+ if (!serializer_xml->head_printed) {
+ xmlTextWriterStartDocument (serializer_xml->writer, "1.0", "UTF-8", NULL);
+ xmlTextWriterStartElement (serializer_xml->writer, "sparql");
+
+ xmlTextWriterStartElement (serializer_xml->writer, "head");
+
+ for (i = 0; i < tracker_sparql_cursor_get_n_columns (cursor); i++) {
+ const gchar *var;
+
+ var = tracker_sparql_cursor_get_variable_name (cursor, i);
+ xmlTextWriterStartElement (serializer_xml->writer, "variable");
+
+ if (var && *var) {
+ g_ptr_array_add (serializer_xml->vars,
+ g_strdup (var));
+ } else {
+ g_ptr_array_add (serializer_xml->vars,
+ g_strdup_printf ("var%d", i + 1));
+ }
+
+ xmlTextWriterWriteFormatAttribute (serializer_xml->writer,
+ "name",
+ "%s",
+ (gchar *) g_ptr_array_index (serializer_xml->vars, i));
+ xmlTextWriterEndElement (serializer_xml->writer);
+ }
+
+ xmlTextWriterEndElement (serializer_xml->writer);
+ xmlTextWriterStartElement (serializer_xml->writer, "results");
+ serializer_xml->head_printed = TRUE;
+ }
+
+ while (!serializer_xml->cursor_finished &&
+ xmlBufferLength (serializer_xml->buffer) < pos) {
+ if (!tracker_sparql_cursor_next (cursor, cancellable, &inner_error)) {
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ } else {
+ xmlTextWriterEndElement (serializer_xml->writer);
+ xmlTextWriterEndElement (serializer_xml->writer);
+ xmlTextWriterEndDocument (serializer_xml->writer);
+ serializer_xml->cursor_finished = TRUE;
+ break;
+ }
+ } else {
+ serializer_xml->cursor_started = TRUE;
+ }
+
+ xmlTextWriterStartElement (serializer_xml->writer, "result");
+
+ for (i = 0; i < tracker_sparql_cursor_get_n_columns (cursor); i++) {
+ const gchar *var, *str, *type, *datatype = NULL;
+
+ if (tracker_sparql_cursor_get_value_type (cursor, i) == TRACKER_SPARQL_VALUE_TYPE_UNBOUND)
+ continue;
+
+ var = g_ptr_array_index (serializer_xml->vars, i);
+
+ xmlTextWriterStartElement (serializer_xml->writer, "binding");
+ xmlTextWriterWriteFormatAttribute (serializer_xml->writer,
+ "name",
+ "%s",
+ var);
+
+ switch (tracker_sparql_cursor_get_value_type (cursor, i)) {
+ case TRACKER_SPARQL_VALUE_TYPE_URI:
+ type = "uri";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_STRING:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "string";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_INTEGER:
+ case TRACKER_SPARQL_VALUE_TYPE_BOOLEAN:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "integer";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_DOUBLE:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "double";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_DATETIME:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "dateTime";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE:
+ type = "bnode";
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ xmlTextWriterStartElement (serializer_xml->writer, type);
+
+ if (datatype) {
+ xmlTextWriterWriteFormatAttribute (serializer_xml->writer,
+ "datatype",
+ "%s",
+ datatype);
+ }
+
+ str = tracker_sparql_cursor_get_string (cursor, i, NULL);
+
+ if (str) {
+ xmlTextWriterWriteRaw (serializer_xml->writer, str);
+ }
+
+ xmlTextWriterEndElement (serializer_xml->writer);
+ xmlTextWriterEndElement (serializer_xml->writer);
+ }
+
+ xmlTextWriterEndElement (serializer_xml->writer);
+ }
+
+ return TRUE;
+}
+
+static gssize
+tracker_serializer_xml_read (GInputStream *istream,
+ gpointer buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSerializerXml *serializer_xml = TRACKER_SERIALIZER_XML (istream);
+ gsize bytes_unflushed, bytes_copied;
+ const xmlChar *xml_buf;
+
+ if (serializer_xml->stream_closed ||
+ (serializer_xml->cursor_finished &&
+ serializer_xml->current_pos == xmlBufferLength (serializer_xml->buffer)))
+ return 0;
+
+ if (!serialize_up_to_position (serializer_xml,
+ serializer_xml->current_pos + count,
+ cancellable,
+ error))
+ return -1;
+
+ bytes_unflushed =
+ xmlBufferLength (serializer_xml->buffer) - serializer_xml->current_pos;
+ bytes_copied = MIN (count, bytes_unflushed);
+
+ xml_buf = xmlBufferContent (serializer_xml->buffer);
+
+ memcpy (buffer,
+ &xml_buf[serializer_xml->current_pos],
+ bytes_copied);
+ serializer_xml->current_pos += bytes_copied;
+
+ return bytes_copied;
+}
+
+static gboolean
+tracker_serializer_xml_close (GInputStream *istream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSerializerXml *serializer_xml = TRACKER_SERIALIZER_XML (istream);
+
+ serializer_xml->stream_closed = TRUE;
+ g_clear_pointer (&serializer_xml->buffer, xmlBufferFree);
+ g_clear_pointer (&serializer_xml->writer, xmlFreeTextWriter);
+
+ return TRUE;
+}
+
+static void
+tracker_serializer_xml_class_init (TrackerSerializerXmlClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS (klass);
+
+ object_class->finalize = tracker_serializer_xml_finalize;
+
+ istream_class->read_fn = tracker_serializer_xml_read;
+ istream_class->close_fn = tracker_serializer_xml_close;
+}
+
+static void
+tracker_serializer_xml_init (TrackerSerializerXml *serializer)
+{
+}
diff --git a/src/libtracker-sparql/tracker-serializer-xml.h b/src/libtracker-sparql/tracker-serializer-xml.h
new file mode 100644
index 000000000..d94bf4eb6
--- /dev/null
+++ b/src/libtracker-sparql/tracker-serializer-xml.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * 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.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef TRACKER_SERIALIZER_XML_H
+#define TRACKER_SERIALIZER_XML_H
+
+#include <libtracker-sparql/tracker-sparql.h>
+#include <libtracker-sparql/tracker-private.h>
+#include <libtracker-sparql/tracker-serializer.h>
+
+#define TRACKER_TYPE_SERIALIZER_XML (tracker_serializer_xml_get_type())
+
+G_DECLARE_FINAL_TYPE (TrackerSerializerXml,
+ tracker_serializer_xml,
+ TRACKER, SERIALIZER_XML,
+ TrackerSerializer);
+
+#endif /* TRACKER_SERIALIZER_XML_H */