[tracker/wip/sam/resource-rebase-6: 7/7] Use TrackerResource instead of TrackerSparqlBuilder in all extractors



commit 43954c51904fce053dd34ac4fb75fcab1e08372c
Author: Sam Thursfield <ssssam gmail com>
Date:   Sun Mar 27 00:15:33 2016 +0000

    Use TrackerResource instead of TrackerSparqlBuilder in all extractors
    
    For a long time, all the Tracker extractors have manually constructed a
    SPARQL update command using TrackerSparqlBuilder to represent their
    output. This commit changes all of them to use the TrackerResource
    class instead, which makes the code a lot more concise and readable.
    
    This introduces some API breaks in the internal libtracker-extract
    library. This has been a private library since Tracker 0.16 or earlier,
    so it's fine.
    
    If the extractors only output SPARQL then they are only useful to
    people who are using a SPARQL store. Now we can output a serialization
    format like Turtle as well. This will hopefully make the extract modules
    useful outside of Tracker itself.
    
    I've tried to preserve the behaviour of the extractors as much as
    possible, but there are two things that are now handled differently:
    
      * nao:Tag resources are given a fixed URI based on the tag label, such
        as <urn:tag:My_Tag>. Previously they were inserted as blank nodes,
        so tracker-store would give them unique IDs like <urn:uuid:1234...>
    
      * All extractors created nco:Contact resources for content publishers,
        but previously some would assign fixed URIs based on the name
        <urn:contact:James%20Joyce>, while others would insert them as blank
        nodes so they would be assigned unique IDs like <urn:uuid:1234...>.
        Now, all extractors create nco:Contact resources with fixed URIs
        based on the content creator's name.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767472

 docs/manpages/tracker-extract.1                    |    7 +-
 src/libtracker-common/tracker-enums.h              |    5 +
 src/libtracker-extract/tracker-data.h              |   61 +--
 src/libtracker-extract/tracker-extract-info.c      |  166 +---
 src/libtracker-extract/tracker-extract-info.h      |   16 +-
 src/libtracker-extract/tracker-guarantee.c         |  143 +++
 src/libtracker-extract/tracker-guarantee.h         |   10 +
 src/libtracker-extract/tracker-resource-helpers.c  |    1 +
 src/libtracker-extract/tracker-xmp.c               |  422 +++-------
 src/libtracker-extract/tracker-xmp.h               |   16 +-
 src/libtracker-sparql/tracker-resource.c           |  451 +++++-----
 src/tracker-extract/tracker-extract-abw.c          |   50 +-
 src/tracker-extract/tracker-extract-bmp.c          |   18 +-
 src/tracker-extract/tracker-extract-decorator.c    |   74 +--
 src/tracker-extract/tracker-extract-dvi.c          |   17 +-
 src/tracker-extract/tracker-extract-epub.c         |  131 +--
 src/tracker-extract/tracker-extract-flac.c         |  254 +-----
 src/tracker-extract/tracker-extract-gif.c          |  348 ++------
 src/tracker-extract/tracker-extract-gstreamer.c    |  911 ++++++--------------
 src/tracker-extract/tracker-extract-html.c         |   39 +-
 src/tracker-extract/tracker-extract-icon.c         |   19 +-
 src/tracker-extract/tracker-extract-iso.c          |   50 +-
 src/tracker-extract/tracker-extract-jpeg.c         |  372 ++-------
 src/tracker-extract/tracker-extract-libav.c        |  232 ++----
 src/tracker-extract/tracker-extract-mp3.c          |  414 +++------
 src/tracker-extract/tracker-extract-msoffice-xml.c |   57 +-
 src/tracker-extract/tracker-extract-msoffice.c     |   81 +-
 src/tracker-extract/tracker-extract-oasis.c        |   65 +-
 src/tracker-extract/tracker-extract-pdf.c          |  301 ++-----
 src/tracker-extract/tracker-extract-playlist.c     |   53 +-
 src/tracker-extract/tracker-extract-png.c          |  348 ++------
 src/tracker-extract/tracker-extract-ps.c           |   77 +-
 src/tracker-extract/tracker-extract-text.c         |   14 +-
 src/tracker-extract/tracker-extract-tiff.c         |  355 ++------
 src/tracker-extract/tracker-extract-vorbis.c       |  279 ++-----
 src/tracker-extract/tracker-extract-xmp.c          |   17 +-
 src/tracker-extract/tracker-extract-xps.c          |   14 +-
 src/tracker-extract/tracker-extract.c              |   93 +--
 src/tracker-extract/tracker-extract.h              |    9 +-
 src/tracker-extract/tracker-main.c                 |   23 +-
 src/tracker/tracker-extract.c                      |   14 +-
 .../libtracker-extract/tracker-extract-info-test.c |   13 +-
 tests/libtracker-extract/tracker-test-xmp.c        |  107 +--
 43 files changed, 1934 insertions(+), 4213 deletions(-)
---
diff --git a/docs/manpages/tracker-extract.1 b/docs/manpages/tracker-extract.1
index 0a7076d..27b630b 100644
--- a/docs/manpages/tracker-extract.1
+++ b/docs/manpages/tracker-extract.1
@@ -22,7 +22,7 @@ For more information see the libtracker-extract reference documentation.
 
 .SH OPTIONS
 .TP
-.B \-\-verbosity\fR=<\fILEVEL\fR>
+.B \-v, \-\-verbosity\fR=<\fILEVEL\fR>
 This sets the log verbosity for the extractor process.
 
 The possible \fILEVEL\fR options are:
@@ -68,6 +68,11 @@ The possible \fILEVEL\fR options are:
 \- Show only warnings, criticals, errors or fatal events.
 .RE
 
+.TP
+.B \-o, \-\-output-format\fR=<\fIFORMAT\fR>
+Choose which format to use to output results. Supported formats are
+\fIsparql\fR and \fIturtle\fR.
+
 .SH EXAMPLES
 .TP
 Using command line to extract metadata from a file:
diff --git a/src/libtracker-common/tracker-enums.h b/src/libtracker-common/tracker-enums.h
index 3fd43d9..2be97c1 100644
--- a/src/libtracker-common/tracker-enums.h
+++ b/src/libtracker-common/tracker-enums.h
@@ -35,6 +35,11 @@ typedef enum {
        TRACKER_SCHED_IDLE_NEVER,
 } TrackerSchedIdle;
 
+typedef enum {
+       TRACKER_SERIALIZATION_FORMAT_SPARQL,
+       TRACKER_SERIALIZATION_FORMAT_TURTLE,
+} TrackerSerializationFormat;
+
 G_END_DECLS
 
 #endif /* __TRACKER_ENUMS_H__ */
diff --git a/src/libtracker-extract/tracker-data.h b/src/libtracker-extract/tracker-data.h
index bdfe82b..05b00db 100644
--- a/src/libtracker-extract/tracker-data.h
+++ b/src/libtracker-extract/tracker-data.h
@@ -24,6 +24,7 @@
 #error "only <libtracker-extract/tracker-extract.h> must be included directly."
 #endif
 
+#include <libtracker-sparql/tracker-resource.h>
 #include <libtracker-sparql/tracker-sparql.h>
 #include "tracker-module-manager.h"
 #include "tracker-extract-info.h"
@@ -31,61 +32,17 @@
 G_BEGIN_DECLS
 
 /**
- * SECTION:tracker-data
- * @title: How to use libtracker-extract
- * @short_description: The essentials by example
- * @stability: Stable
+ * SECTION:tracker-extract
+ * @title: libtracker-extract
+ * @stability: Unstable
  * @include: libtracker-extract/tracker-extract.h
  *
- * The libtracker-extract library is the foundation for Tracker
- * metadata extraction of embedded data in files.
+ * The libtracker-extract library is an internal, private library for Tracker
+ * metadata extraction modules. Third party applications should not link
+ * against libtracker-extract, because its API may change at any time.
  *
- * Tracker comes with extractors written for the most common file
- * types (like MP3, JPEG, PNG, etc.), however, for more special cases,
- * 3rd party applications may want to write their own plugin to
- * extract their own file formats. This documentation describes how to
- * do that.
- *
- * <example>
- * <title>Basic extractor example</title>
- * An example of how to write an extractor to retrieve PNG embedded
- * metadata.
- * <programlisting>
- *  G_MODULE_EXPORT gboolean
- *  tracker_extract_get_metadata (TrackerExtractInfo *info)
- *  {
- *          GFile *file;
- *          TrackerSparqlBuilder *metadata;
- *          gint height, width;
- *
- *          file = tracker_extract_info_get_file (info);
- *          metadata = tracker_extract_info_get_metadata_builder (info);
- *
- *          /&ast; Do data extraction. &ast;/
- *          height = ...
- *          width = ...
- *
- *          /&ast; Insert data into TrackerSparqlBuilder object. &ast;/
- *          tracker_sparql_builder_predicate (metadata, "a");
- *          tracker_sparql_builder_object (metadata, "nfo:Image");
- *          tracker_sparql_builder_object (metadata, "nmm:Photo");
- *
- *          tracker_sparql_builder_predicate (metadata, "nfo:width");
- *          tracker_sparql_builder_object_int64 (metadata, width);
- *
- *          tracker_sparql_builder_predicate (metadata, "nfo:height");
- *          tracker_sparql_builder_object_int64 (metadata, height);
- *
- *          /&ast; Were we successful or not? &ast;/
- *          return TRUE;
- *  }
- * </programlisting>
- * </example>
- *
- * NOTE: This example has changed subtly since 0.10. For details see
- * tracker_extract_get_metadata().
- *
- * Since: 0.12
+ * If you want to insert metadata into the Tracker store from a 3rd party
+ * application, look at the TrackerDecorator class from libtracker-miner.
  */
 
 gboolean tracker_extract_module_init     (TrackerModuleThreadAwareness  *thread_awareness_ret,
diff --git a/src/libtracker-extract/tracker-extract-info.c b/src/libtracker-extract/tracker-extract-info.c
index c534695..90c2836 100644
--- a/src/libtracker-extract/tracker-extract-info.c
+++ b/src/libtracker-extract/tracker-extract-info.c
@@ -39,15 +39,10 @@
 
 struct _TrackerExtractInfo
 {
-       TrackerSparqlBuilder *preupdate;
-       TrackerSparqlBuilder *postupdate;
-       TrackerSparqlBuilder *metadata;
-       gchar *where_clause;
+       TrackerResource *resource;
 
        GFile *file;
        gchar *mimetype;
-       gchar *graph;
-       gchar *urn;
 
 #ifdef HAVE_LIBMEDIAART
        MediaArtProcess *media_art_process;
@@ -73,9 +68,7 @@ G_DEFINE_BOXED_TYPE (TrackerExtractInfo, tracker_extract_info,
  **/
 TrackerExtractInfo *
 tracker_extract_info_new (GFile       *file,
-                          const gchar *mimetype,
-                          const gchar *graph,
-                          const gchar *urn)
+                          const gchar *mimetype)
 {
        TrackerExtractInfo *info;
 
@@ -84,14 +77,8 @@ tracker_extract_info_new (GFile       *file,
        info = g_slice_new0 (TrackerExtractInfo);
        info->file = g_object_ref (file);
        info->mimetype = g_strdup (mimetype);
-       info->graph = g_strdup (graph);
-       info->urn = g_strdup (urn);
 
-       info->preupdate = tracker_sparql_builder_new_update ();
-       info->postupdate = tracker_sparql_builder_new_update ();
-       info->metadata = tracker_sparql_builder_new_embedded_insert ();
-
-        info->where_clause = NULL;
+       info->resource = NULL;
 
 #ifdef HAVE_LIBMEDIAART
         info->media_art_process = NULL;
@@ -139,13 +126,9 @@ tracker_extract_info_unref (TrackerExtractInfo *info)
        if (g_atomic_int_dec_and_test (&info->ref_count)) {
                g_object_unref (info->file);
                g_free (info->mimetype);
-               g_free (info->graph);
-               g_free (info->urn);
 
-               g_object_unref (info->preupdate);
-               g_object_unref (info->postupdate);
-               g_object_unref (info->metadata);
-               g_free (info->where_clause);
+               if (info->resource)
+                       g_object_unref (info->resource);
 
 #ifdef HAVE_LIBMEDIAART
                if (info->media_art_process)
@@ -195,131 +178,60 @@ tracker_extract_info_get_mimetype (TrackerExtractInfo *info)
        return info->mimetype;
 }
 
-/**
- * tracker_extract_info_get_graph:
- * @info: a #TrackerExtractInfo
- *
- * Returns the SPARQL graph that will be used when
- * inserting metadata.
- *
- * Returns: (transfer none): The SPARQL graph the extract
- *          operation belongs to.
- *
- * Since: 0.12
- **/
-const gchar *
-tracker_extract_info_get_graph (TrackerExtractInfo *info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->graph;
-}
 
 /**
- * tracker_extract_info_get_preupdate_builder:
+ * tracker_extract_info_get_resource:
  * @info: a #TrackerExtractInfo
  *
- * Returns a #TrackerSparqlBuilder containing any
- * separate updates that could apply to the file,
- * such as author/band information in audio files,
- * and so on.
+ * Returns the #TrackerResource representing metadata about the file
+ * associated with this #TrackerExtractInfo, or %NULL if
+ * tracker_extract_info_set_metadata() was not yet called.
  *
- * Returns: (transfer none): miscellaneous metadata
+ * Returns: (transfer none): a #TrackerResource instance
  *
- * Since: 0.12
- **/
-TrackerSparqlBuilder *
-tracker_extract_info_get_preupdate_builder (TrackerExtractInfo *info)
+ * Since: 1.10
+ */
+TrackerResource *
+tracker_extract_info_get_resource (TrackerExtractInfo *info)
 {
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->preupdate;
+       return info->resource;
 }
 
 /**
- * tracker_extract_info_get_postupdate_builder:
+ * tracker_extract_info_set_resource:
  * @info: a #TrackerExtractInfo
+ * @resource: a #TrackerResource
  *
- * Returns a #TrackerSparqlBuilder containing separate
- * updates for resources that are contained within the file
- * and need to refer to it.
+ * Adds the #TrackerResource with results from the extraction to this
+ * #TrackerExtractInfo.
  *
- * Returns: (transfer none): #TrackerSparqlBuilder for
- * resources that need inserting after the file resource.
+ * Information about the file itself should be represented by properties of
+ * @resource itself. It's expected this resource will have nfo:FileDataObject
+ * as one of its types. This @resource can have related resources attached to
+ * it.
  *
- * Since: 0.12.4
- **/
-TrackerSparqlBuilder *
-tracker_extract_info_get_postupdate_builder (TrackerExtractInfo *info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->postupdate;
-}
-
-/**
- * tracker_extract_info_get_metadata_builder:
- * @info: a #TrackerExtractInfo
+ * In most cases, a file contains a single logical resource. Most MP3 files
+ * contain one song, for example. In this case you set all properties on the
+ * one @resource.
  *
- * Returns a #TrackerSparqlBuilder containing the
- * file metadata.
+ * In more complex cases, a single physical resource (i.e. a file) contains multiple
+ * logical resources: for example, an MBOX file holding multiple emails, or
+ * an audio file containing an entire CD. In this case you should treat each
+ * logical resource as its own #TrackerResource. Only properties of the file
+ * itself should be set on @resource. You then relate each logical
+ * #TrackerResource to the main @resource using the nie:isStoredAs property.
  *
- * Returns: (transfer none): the file metadata
+ * FIXME: you need a way to delete the logical resources when re-extracting a
+ * file -- still need to decide on API for that.
  *
- * Since: 0.12
- **/
-TrackerSparqlBuilder *
-tracker_extract_info_get_metadata_builder (TrackerExtractInfo *info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->metadata;
-}
-
-/**
- * tracker_extract_info_get_where_clause:
- * @info: a #TrackerExtractInfo
- *
- * Returns the where clause that will apply to the
- * other metadata contained in @info.
- *
- * Returns: (transfer none): The where clause
- *
- * Since: 0.12
- **/
-const gchar *
-tracker_extract_info_get_where_clause (TrackerExtractInfo *info)
-{
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->where_clause;
-}
-
-/**
- * tracker_extract_info_set_where_clause:
- * @info: a #TrackerExtractInfo
- * @where: Where clause for the file update.
- *
- * Sets the where clause for the returned metadata.
- *
- * Since: 0.12
+ * Since: 1.10
  **/
 void
-tracker_extract_info_set_where_clause (TrackerExtractInfo *info,
-                                       const gchar        *where)
-{
-       g_return_if_fail (info != NULL);
-
-       g_free (info->where_clause);
-       info->where_clause = g_strdup (where);
-}
-
-const gchar *
-tracker_extract_info_get_urn (TrackerExtractInfo *info)
+tracker_extract_info_set_resource (TrackerExtractInfo *info,
+                                   TrackerResource    *resource)
 {
-       g_return_val_if_fail (info != NULL, NULL);
-
-       return info->urn;
+       g_object_ref (resource);
+       info->resource = resource;
 }
 
 #ifdef HAVE_LIBMEDIAART
diff --git a/src/libtracker-extract/tracker-extract-info.h b/src/libtracker-extract/tracker-extract-info.h
index 857956f..5036f8d 100644
--- a/src/libtracker-extract/tracker-extract-info.h
+++ b/src/libtracker-extract/tracker-extract-info.h
@@ -40,21 +40,15 @@ typedef struct _TrackerExtractInfo TrackerExtractInfo;
 GType                 tracker_extract_info_get_type               (void) G_GNUC_CONST;
 
 TrackerExtractInfo *  tracker_extract_info_new                    (GFile              *file,
-                                                                   const gchar        *mimetype,
-                                                                   const gchar        *graph,
-                                                                   const gchar        *urn);
+                                                                   const gchar        *mimetype);
 TrackerExtractInfo *  tracker_extract_info_ref                    (TrackerExtractInfo *info);
 void                  tracker_extract_info_unref                  (TrackerExtractInfo *info);
 GFile *               tracker_extract_info_get_file               (TrackerExtractInfo *info);
 const gchar *         tracker_extract_info_get_mimetype           (TrackerExtractInfo *info);
-const gchar *         tracker_extract_info_get_graph              (TrackerExtractInfo *info);
-const gchar *         tracker_extract_info_get_urn                (TrackerExtractInfo *info);
-TrackerSparqlBuilder *tracker_extract_info_get_preupdate_builder  (TrackerExtractInfo *info);
-TrackerSparqlBuilder *tracker_extract_info_get_postupdate_builder (TrackerExtractInfo *info);
-TrackerSparqlBuilder *tracker_extract_info_get_metadata_builder   (TrackerExtractInfo *info);
-const gchar *         tracker_extract_info_get_where_clause       (TrackerExtractInfo *info);
-void                  tracker_extract_info_set_where_clause       (TrackerExtractInfo *info,
-                                                                   const gchar        *where);
+
+TrackerResource *     tracker_extract_info_get_resource           (TrackerExtractInfo *info);
+void                  tracker_extract_info_set_resource           (TrackerExtractInfo *info,
+                                                                   TrackerResource    *resource);
 
 #ifdef HAVE_LIBMEDIAART
 
diff --git a/src/libtracker-extract/tracker-guarantee.c b/src/libtracker-extract/tracker-guarantee.c
index f43a4e6..9b8460a 100644
--- a/src/libtracker-extract/tracker-guarantee.c
+++ b/src/libtracker-extract/tracker-guarantee.c
@@ -87,6 +87,9 @@ get_date_from_file_mtime (const gchar *uri)
  * (before the "." and extension of the file) as the title. If the
  * title has any "_" characters, they are also converted into spaces.
  *
+ * This function only operates if Tracker was compiled with
+ * --enable-guarantee-metadata enabled at configure-time.
+ *
  * Returns: %TRUE on success and content was added to @metadata, otherwise %FALSE.
  *
  * Since: 0.10
@@ -160,6 +163,9 @@ tracker_guarantee_title_from_file (TrackerSparqlBuilder  *metadata,
  * When parsing @uri, stat() is called on the file to create a
  * date based on the file's mtime.
  *
+ * This function only operates if Tracker was compiled with
+ * --enable-guarantee-metadata enabled at configure-time.
+ *
  * Returns: %TRUE on success and content was added to @metadata, otherwise %FALSE.
  *
  * Since: 0.10
@@ -205,3 +211,140 @@ tracker_guarantee_date_from_file_mtime (TrackerSparqlBuilder *metadata,
 
        return success;
 }
+
+
+/**
+ * tracker_guarantee_resource_title_from_file:
+ * @resource: the relevant #TrackerResource
+ * @key: the property URI to set
+ * @current_value: the current data to check before looking at @uri.
+ * @uri: a string representing a URI to use
+ * @p_new_value: pointer to a string which receives the new title, or
+ *             %NULL
+ *
+ * Checks @current_value to make sure it is usable (i.e. not %NULL or an
+ * empty string). If it is not usable, then @uri is parsed to guarantee a
+ * metadata value for @key.
+ *
+ * Parses the file pointed to by @uri and uses the basename
+ * (before the "." and extension of the file) as the title. If the
+ * title has any "_" characters, they are also converted into spaces.
+ *
+ * This function only operates if Tracker was compiled with
+ * --enable-guarantee-metadata enabled at configure-time.
+ *
+ * Returns: %TRUE on success and content was added to @metadata, otherwise %FALSE.
+ *
+ * Since: 1.10
+ **/
+gboolean
+tracker_guarantee_resource_title_from_file (TrackerResource  *resource,
+                                            const gchar      *key,
+                                            const gchar      *current_value,
+                                            const gchar      *uri,
+                                            gchar           **p_new_value)
+{
+       gboolean success = TRUE;
+
+#ifdef GUARANTEE_METADATA
+       g_return_val_if_fail (metadata != NULL, FALSE);
+       g_return_val_if_fail (key != NULL, FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       if (current_value && *current_value != '\0') {
+               tracker_resource_set_string (resource, key, current_value);
+
+               if (p_new_value != NULL) {
+                       *p_new_value = g_strdup (current_value);
+               }
+       } else {
+               gchar *value;
+
+               value = get_title_from_file (uri);
+
+               if (value && value[0] != '\0') {
+                       tracker_resource_set_string (resource, key, value);
+               } else {
+                       success = FALSE;
+               }
+
+               if (p_new_value != NULL) {
+                       *p_new_value = value;
+               } else {
+                       g_free (value);
+               }
+       }
+#else  /* GUARANTEE_METADATA */
+       if (current_value && *current_value != '\0') {
+               tracker_resource_set_string (resource, key, current_value);
+
+               if (p_new_value != NULL) {
+                       *p_new_value = g_strdup (current_value);
+               }
+       } else {
+               success = FALSE;
+       }
+#endif /* GUARANTEE_METADATA */
+
+       return success;
+}
+
+/**
+ * tracker_guarantee_resource_date_from_file_mtime:
+ * @resource: the relevant #TrackerResource
+ * @key: the property URI to set
+ * @current_value: the current data to check before looking at @uri
+ * @uri: a string representing a URI to use
+ *
+ * Checks @current_value to make sure it is sane (i.e. not %NULL or an
+ * empty string). If it is, then @uri is parsed to guarantee a
+ * metadata value for @key.
+ *
+ * When parsing @uri, stat() is called on the file to create a
+ * date based on the file's mtime.
+ *
+ * This function only operates if Tracker was compiled with
+ * --enable-guarantee-metadata enabled at configure-time.
+ *
+ * Returns: %TRUE on success and content was added to @metadata, otherwise %FALSE.
+ *
+ * Since: 1.10
+ **/
+gboolean
+tracker_guarantee_resource_date_from_file_mtime (TrackerResource *resource,
+                                                 const gchar     *key,
+                                                 const gchar     *current_value,
+                                                 const gchar     *uri)
+{
+       gboolean success = TRUE;
+
+#ifdef GUARANTEE_METADATA
+       g_return_val_if_fail (resource != NULL, FALSE);
+       g_return_val_if_fail (key != NULL, FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       if (current_value && *current_value != '\0') {
+               tracker_resource_set_string (resource, key, current_value);
+       } else {
+               gchar *value;
+
+               value = get_date_from_file_mtime (uri);
+
+               if (value && *value != '\0') {
+                       tracker_resource_set_string (resource, key, value);
+               } else {
+                       success = FALSE;
+               }
+
+               g_free (value);
+       }
+#else  /* GUARANTEE_METADATA */
+       if (current_value && *current_value != '\0') {
+               tracker_resource_set_string (resource, key, current_value);
+       } else {
+               success = FALSE;
+       }
+#endif /* GUARANTEE_METADATA */
+
+       return success;
+}
diff --git a/src/libtracker-extract/tracker-guarantee.h b/src/libtracker-extract/tracker-guarantee.h
index e14fd8e..9b58a63 100644
--- a/src/libtracker-extract/tracker-guarantee.h
+++ b/src/libtracker-extract/tracker-guarantee.h
@@ -40,6 +40,16 @@ gboolean tracker_guarantee_date_from_file_mtime (TrackerSparqlBuilder *metadata,
                                                  const gchar          *current_value,
                                                  const gchar          *uri);
 
+gboolean tracker_guarantee_resource_title_from_file      (TrackerResource  *resource,
+                                                          const gchar      *key,
+                                                          const gchar      *current_value,
+                                                          const gchar      *uri,
+                                                          gchar           **p_new_value);
+gboolean tracker_guarantee_resource_date_from_file_mtime (TrackerResource  *resource,
+                                                          const gchar      *key,
+                                                          const gchar      *current_value,
+                                                          const gchar      *uri);
+
 G_END_DECLS
 
 #endif /*  __LIBTRACKER_EXTRACT_GUARANTEE_H__ */
diff --git a/src/libtracker-extract/tracker-resource-helpers.c 
b/src/libtracker-extract/tracker-resource-helpers.c
index 4c33012..95b92c6 100644
--- a/src/libtracker-extract/tracker-resource-helpers.c
+++ b/src/libtracker-extract/tracker-resource-helpers.c
@@ -264,6 +264,7 @@ tracker_extract_new_music_album_disc (const char      *album_title,
 
        disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d", album_title, disc_number);
        album_disc = tracker_resource_new (disc_uri);
+       tracker_resource_set_uri (album_disc, "rdf:type", "nmm:MusicAlbumDisc");
        tracker_resource_set_int (album_disc, "nmm:setNumber", disc_number > 0 ? disc_number : 1);
        tracker_resource_add_relation (album_disc, "nmm:albumDiscAlbum", album);
 
diff --git a/src/libtracker-extract/tracker-xmp.c b/src/libtracker-extract/tracker-xmp.c
index dda8368..76110ff 100644
--- a/src/libtracker-extract/tracker-xmp.c
+++ b/src/libtracker-extract/tracker-xmp.c
@@ -23,6 +23,7 @@
 
 #include <libtracker-common/tracker-utils.h>
 
+#include "tracker-resource-helpers.h"
 #include "tracker-xmp.h"
 #include "tracker-utils.h"
 
@@ -867,40 +868,28 @@ fix_region_type (const gchar *region_type)
 
 
 /**
- * tracker_xmp_apply:
- * @preupdate: the preupdate object to apply XMP data to.
- * @metadata: the metadata object to apply XMP data to.
- * @graph: the graph to apply XMP data to.
- * @where: the where object.
- * @uri: the URI this is related to.
- * @data: the data to push into @metadata.
- *
- * This function applies all data in @data to @metadata.
+ * tracker_xmp_apply_to_resource:
+ * @resource: the #TrackerResource to apply XMP data to.
+ * @data: the data to push into @resource.
  *
- * The @graph parameter was added in 0.12.
+ * This function applies all data in @data to @resource.
  *
- * This function also calls tracker_xmp_apply_regions(), so there is
- * no need to call both functions.
+ * This function also calls tracker_xmp_apply_regions_to_resource(), so there
+ * is no need to call both functions.
  *
- * Returns: %TRUE if the @data was applied to @metadata successfully,
+ * Returns: %TRUE if the @data was applied to @resource successfully,
  * otherwise %FALSE is returned.
  *
- * Since: 0.8
+ * Since: 1.10
  **/
 gboolean
-tracker_xmp_apply (TrackerSparqlBuilder *preupdate,
-                   TrackerSparqlBuilder *metadata,
-                   const gchar          *graph,
-                   GString              *where,
-                   const gchar          *uri,
-                   TrackerXmpData       *data)
+tracker_xmp_apply_to_resource (TrackerResource *resource,
+                               TrackerXmpData  *data)
 {
        GPtrArray *keywords;
        guint i;
 
-       g_return_val_if_fail (TRACKER_SPARQL_IS_BUILDER (preupdate), FALSE);
-       g_return_val_if_fail (TRACKER_SPARQL_IS_BUILDER (metadata), FALSE);
-       g_return_val_if_fail (uri != NULL, FALSE);
+       g_return_val_if_fail (TRACKER_IS_RESOURCE (resource), FALSE);
        g_return_val_if_fail (data != NULL, FALSE);
 
        keywords = g_ptr_array_new ();
@@ -918,133 +907,65 @@ tracker_xmp_apply (TrackerSparqlBuilder *preupdate,
        }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *p, *escaped, *var;
+               TrackerResource *label;
+               gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               var = g_strdup_printf ("tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_append (preupdate,
-                                              "INSERT { ");
-
-               if (graph) {
-                       tracker_sparql_builder_append (preupdate, "GRAPH <");
-                       tracker_sparql_builder_append (preupdate, graph);
-                       tracker_sparql_builder_append (preupdate, "> { ");
-               }
-
-               tracker_sparql_builder_append (preupdate,"_:tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-
-               if (graph) {
-                       tracker_sparql_builder_append (preupdate, " } ");
-               }
+               label = tracker_extract_new_tag (p);
 
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }\nWHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
+               tracker_resource_set_relation (resource, "nao:hasTag", label);
 
-               /* associate file with tag */
-               tracker_sparql_builder_predicate (metadata, "nao:hasTag");
-               tracker_sparql_builder_object_variable (metadata, var);
-
-               g_string_append_printf (where, "?%s a nao:Tag ; nao:prefLabel \"%s\" .\n", var, escaped);
-
-               g_free (var);
-               g_free (escaped);
                g_free (p);
+               g_object_unref (label);
        }
        g_ptr_array_free (keywords, TRUE);
 
        if (data->publisher) {
-               tracker_sparql_builder_predicate (metadata, "nco:publisher");
-
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
+               TrackerResource *publisher;
 
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, data->publisher);
-               tracker_sparql_builder_object_blank_close (metadata);
+               publisher = tracker_extract_new_contact (data->publisher);
+               tracker_resource_set_relation (resource, "nco:publisher", publisher);
+               g_object_unref (publisher);
        }
 
        if (data->type) {
-               tracker_sparql_builder_predicate (metadata, "dc:type");
-               tracker_sparql_builder_object_unvalidated (metadata, data->type);
+               tracker_resource_set_string (resource, "dc:type", data->type);
        }
 
        if (data->format) {
-               tracker_sparql_builder_predicate (metadata, "dc:format");
-               tracker_sparql_builder_object_unvalidated (metadata, data->format);
+               tracker_resource_set_string (resource, "dc:format", data->format);
        }
 
        if (data->identifier) {
-               tracker_sparql_builder_predicate (metadata, "dc:identifier");
-               tracker_sparql_builder_object_unvalidated (metadata, data->identifier);
+               tracker_resource_set_string (resource, "dc:identifier", data->identifier);
        }
 
        if (data->source) {
-               tracker_sparql_builder_predicate (metadata, "dc:source");
-               tracker_sparql_builder_object_unvalidated (metadata, data->source);
+               tracker_resource_set_string (resource, "dc:source", data->source);
        }
 
        if (data->language) {
-               tracker_sparql_builder_predicate (metadata, "dc:language");
-               tracker_sparql_builder_object_unvalidated (metadata, data->language);
+               tracker_resource_set_string (resource, "dc:language", data->language);
        }
 
        if (data->relation) {
-               tracker_sparql_builder_predicate (metadata, "dc:relation");
-               tracker_sparql_builder_object_unvalidated (metadata, data->relation);
+               tracker_resource_set_string (resource, "dc:relation", data->relation);
        }
 
        if (data->coverage) {
-               tracker_sparql_builder_predicate (metadata, "dc:coverage");
-               tracker_sparql_builder_object_unvalidated (metadata, data->coverage);
+               tracker_resource_set_string (resource, "dc:coverage", data->coverage);
        }
 
        if (data->license) {
-               tracker_sparql_builder_predicate (metadata, "dc:license");
-               tracker_sparql_builder_object_unvalidated (metadata, data->license);
+               tracker_resource_set_string (resource, "dc:license", data->license);
        }
 
        if (data->make || data->model) {
-               gchar *equip_uri;
-
-               equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                             data->make ? data->make : "",
-                                                             data->model ? data->model : "");
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:Equipment");
-
-               if (data->make) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                       tracker_sparql_builder_object_unvalidated (preupdate, data->make);
-               }
-               if (data->model) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                       tracker_sparql_builder_object_unvalidated (preupdate, data->model);
-               }
+               TrackerResource *equipment;
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-               tracker_sparql_builder_object_iri (metadata, equip_uri);
-               g_free (equip_uri);
+               equipment = tracker_extract_new_equipment (data->make, data->model);
+               tracker_resource_set_relation (resource, "nfo:equipment", equipment);
+               g_object_unref (equipment);
        }
 
        if (data->title || data->title2 || data->pdf_title) {
@@ -1052,283 +973,176 @@ tracker_xmp_apply (TrackerSparqlBuilder *preupdate,
                                                                   data->title2,
                                                                   data->pdf_title);
 
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_unvalidated (metadata, final_title);
+               tracker_resource_set_string (resource, "nie:title", final_title);
        }
 
        if (data->orientation) {
-               tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-               tracker_sparql_builder_object_unvalidated (metadata, data->orientation);
+               tracker_resource_set_string (resource, "nfo:orientation", data->orientation);
        }
 
        if (data->rights || data->copyright) {
                const gchar *final_rights = tracker_coalesce_strip (2, data->copyright, data->rights);
 
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, final_rights);
+               tracker_resource_set_string (resource, "nie:copyright", final_rights);
        }
 
        if (data->white_balance) {
-               tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-               tracker_sparql_builder_object_unvalidated (metadata, data->white_balance);
+               tracker_resource_set_string (resource, "nmm:whiteBalance", data->white_balance);
        }
 
        if (data->fnumber) {
-               tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-               tracker_sparql_builder_object_unvalidated (metadata, data->fnumber);
+               tracker_resource_set_string (resource, "nmm:fnumber", data->fnumber);
        }
 
        if (data->flash) {
-               tracker_sparql_builder_predicate (metadata, "nmm:flash");
-               tracker_sparql_builder_object_unvalidated (metadata, data->flash);
+               tracker_resource_set_string (resource, "nmm:flash", data->flash);
        }
 
        if (data->focal_length) {
-               tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-               tracker_sparql_builder_object_unvalidated (metadata, data->focal_length);
+               tracker_resource_set_string (resource, "nmm:focalLength", data->focal_length);
        }
 
        if (data->artist || data->contributor) {
+               TrackerResource *contributor;
                const gchar *final_artist = tracker_coalesce_strip (2, data->artist, data->contributor);
 
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
-
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, final_artist);
-               tracker_sparql_builder_object_blank_close (metadata);
+               contributor = tracker_extract_new_contact (final_artist);
+               tracker_resource_set_relation (resource, "nco:contributor", contributor);
+               g_object_unref (contributor);
        }
 
        if (data->exposure_time) {
-               tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-               tracker_sparql_builder_object_unvalidated (metadata, data->exposure_time);
+               tracker_resource_set_string (resource, "nmm:exposureTime", data->exposure_time);
        }
 
        if (data->iso_speed_ratings) {
-               tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-               tracker_sparql_builder_object_unvalidated (metadata, data->iso_speed_ratings);
+               tracker_resource_set_string (resource, "nmm:isoSpeed", data->iso_speed_ratings);
        }
 
        if (data->date || data->time_original) {
                const gchar *final_date = tracker_coalesce_strip (2, data->date,
                                                                  data->time_original);
 
-               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-               tracker_sparql_builder_object_unvalidated (metadata, final_date);
+               tracker_resource_set_string (resource, "nie:contentCreated", final_date);
        }
 
        if (data->description) {
-               tracker_sparql_builder_predicate (metadata, "nie:description");
-               tracker_sparql_builder_object_unvalidated (metadata, data->description);
+               tracker_resource_set_string (resource, "nie:description", data->description);
        }
 
        if (data->metering_mode) {
-               tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-               tracker_sparql_builder_object_unvalidated (metadata, data->metering_mode);
+               tracker_resource_set_string (resource, "nmm:meteringMode", data->metering_mode);
        }
 
        if (data->creator) {
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
+               TrackerResource *creator;
 
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, data->creator);
-               tracker_sparql_builder_object_blank_close (metadata);
+               creator = tracker_extract_new_contact (data->creator);
+               tracker_resource_set_relation (resource, "nco:creator", creator);
+               g_object_unref (creator);
        }
 
        if (data->address || data->state || data->country || data->city ||
            data->gps_altitude || data->gps_latitude || data->gps_longitude) {
+               TrackerResource *geopoint;
 
-               tracker_sparql_builder_predicate (metadata, "slo:location");
-
-               tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
-
-               if (data->address || data->state || data->country || data->city) {
-                       gchar *addruri;
-
-                       addruri = tracker_sparql_get_uuid_urn ();
-
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, addruri);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, addruri);
-
-                       g_free (addruri);
-
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
-
-                       if (data->address) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                               tracker_sparql_builder_object_unvalidated (preupdate, data->address);
-                       }
-
-                       if (data->state) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:region");
-                               tracker_sparql_builder_object_unvalidated (preupdate, data->state);
-                       }
-
-                       if (data->city) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                               tracker_sparql_builder_object_unvalidated (preupdate, data->city);
-                       }
-
-                       if (data->country) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:country");
-                               tracker_sparql_builder_object_unvalidated (preupdate, data->country);
-                       }
-
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-
-               /* FIXME We are not handling the altitude ref here */
-
-               if (data->gps_altitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, data->gps_altitude);
-               }
-
-               if (data->gps_latitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, data->gps_latitude);
-               }
-
-               if (data->gps_longitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, data->gps_longitude);
-               }
-
-               tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+               geopoint = tracker_extract_new_location (data->address, data->state, data->city,
+                       data->country, data->gps_altitude, data->gps_latitude, data->gps_longitude);
+               tracker_resource_set_relation (resource, "slo:location", geopoint);
+               g_object_unref (geopoint);
        }
 
        if (data->gps_direction) {
-               tracker_sparql_builder_predicate (metadata, "nfo:heading");
-               tracker_sparql_builder_object_unvalidated (metadata, data->gps_direction);
+               tracker_resource_set_string (resource, "nfo:heading", data->gps_direction);
        }
 
-
-        if (data->regions) {
-               tracker_xmp_apply_regions (preupdate, metadata, graph, data);
-        }
+       if (data->regions) {
+               tracker_xmp_apply_regions_to_resource (resource, data);
+       }
 
        return TRUE;
 }
 
 /**
- * tracker_xmp_apply_regions:
- * @preupdate: the preupdate object to apply XMP data to.
- * @metadata: the metadata object to apply XMP data to.
- * @graph: the graph to apply XMP data to.
- * @data: the data to push into @preupdate and @metadata.
+ * tracker_xmp_apply_regions_to_resource:
+ * @resource: the #TrackerResource object to apply XMP data to.
+ * @data: the data to push into @resource
  *
- * This function applies all regional @data to @preupdate and
- * @metadata. Regional data exists for image formats like JPEG, PNG,
- * etc. where parts of the image refer to areas of interest. This can
- * be people's faces, places to focus, barcodes, etc. The regional
- * data describes the title, height, width, X, Y and can occur
- * multiple times in a given file.
+ * This function applies all regional @data to @resource. Regional data exists
+ * for image formats like JPEG, PNG, etc. where parts of the image refer to
+ * areas of interest. This can be people's faces, places to focus, barcodes,
+ * etc. The regional data describes the title, height, width, X, Y and can
+ * occur multiple times in a given file.
  *
  * This data usually is standardized between image formats and that's
- * what makes this function different to tracker_xmp_apply() which is
- * useful for XMP files only.
+ * what makes this function different to tracker_xmp_apply_to_resource() which
+ * is useful for XMP files only.
  *
- * Returns: %TRUE if the @data was applied to @preupdate and @metadata
- * successfully, otherwise %FALSE is returned.
+ * Returns: %TRUE if the @data was applied to @resource successfully, otherwise
+ * %FALSE is returned.
  *
- * Since: 0.12
+ * Since: 1.10
  **/
 gboolean
-tracker_xmp_apply_regions (TrackerSparqlBuilder *preupdate,
-                           TrackerSparqlBuilder *metadata,
-                           const gchar          *graph,
-                           TrackerXmpData       *data)
+tracker_xmp_apply_regions_to_resource (TrackerResource *resource,
+                                       TrackerXmpData  *data)
 {
-        GSList *iter;
+       GSList *iter;
 
-        g_return_val_if_fail (TRACKER_SPARQL_IS_BUILDER (preupdate), FALSE);
-        g_return_val_if_fail (TRACKER_SPARQL_IS_BUILDER (metadata), FALSE);
-        g_return_val_if_fail (data != NULL, FALSE);
+       g_return_val_if_fail (TRACKER_IS_RESOURCE (resource), FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
 
-        if (!data->regions) {
-                return TRUE;
-        }
+       if (!data->regions) {
+               return TRUE;
+       }
 
-        for (iter = data->regions; iter != NULL; iter = iter->next) {
-               TrackerXmpRegion *region;
-               gchar *uuid;
+       for (iter = data->regions; iter != NULL; iter = iter->next) {
+               TrackerResource *region_resource;
+               TrackerXmpRegion *region;
+               gchar *uuid;
 
-                region = (TrackerXmpRegion *) iter->data;
-                uuid = tracker_sparql_get_uuid_urn ();
+               region = (TrackerXmpRegion *) iter->data;
+               uuid = tracker_sparql_get_uuid_urn ();
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               region_resource = tracker_resource_new (uuid);
+               tracker_resource_set_uri (region_resource, "rdf:type", "nfo:RegionOfInterest");
 
-               tracker_sparql_builder_subject_iri (preupdate, uuid);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:RegionOfInterest");
+               g_free (uuid);
 
-                if (region->title) {
-                        tracker_sparql_builder_predicate (preupdate, "nie:title");
-                        tracker_sparql_builder_object_string (preupdate, region->title);
-                }
-
-                if (region->description) {
-                        tracker_sparql_builder_predicate (preupdate, "nie:description");
-                        tracker_sparql_builder_object_string (preupdate, region->description);
-                }
-
-                if (region->type) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:regionOfInterestType");
-                        tracker_sparql_builder_object (preupdate, fix_region_type (region->type));
-                }
+               if (region->title) {
+                       tracker_resource_set_string (region_resource, "nie:title", region->title);
+               }
 
-                if (region->x) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:regionOfInterestX");
-                        tracker_sparql_builder_object_unvalidated (preupdate, region->x);
-                }
+               if (region->description) {
+                       tracker_resource_set_string (region_resource, "nie:description", region->description);
+               }
 
-                if (region->y) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:regionOfInterestY");
-                        tracker_sparql_builder_object_unvalidated (preupdate, region->y);
-                }
+               if (region->type) {
+                       tracker_resource_set_string (region_resource, "nfo:regionOfInterestType", 
fix_region_type (region->type));
+               }
 
-                if (region->width) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:regionOfInterestWidth");
-                        tracker_sparql_builder_object_unvalidated (preupdate, region->width);
-                }
+               if (region->x) {
+                       tracker_resource_set_string (region_resource, "nfo:regionOfInterestX", region->x);
+               }
 
-                if (region->height) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:regionOfInterestHeight");
-                        tracker_sparql_builder_object_unvalidated (preupdate, region->height);
-                }
+               if (region->y) {
+                       tracker_resource_set_string (region_resource, "nfo:regionOfInterestY", region->y);
+               }
 
-                if (region->link_uri && region->link_class) {
-                        tracker_sparql_builder_predicate (preupdate, "nfo:roiRefersTo");
-                        tracker_sparql_builder_object_iri (preupdate, region->link_uri);
-                }
+               if (region->width) {
+                       tracker_resource_set_string (region_resource, "nfo:regionOfInterestWidth", 
region->width);
+               }
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
+               if (region->height) {
+                       tracker_resource_set_string (region_resource, "nfo:regionOfInterestHeight", 
region->height);
                }
-               tracker_sparql_builder_insert_close (preupdate);
 
-                /* Handle non-preupdate metadata */
-                tracker_sparql_builder_predicate (metadata, "nfo:hasRegionOfInterest");
-                tracker_sparql_builder_object_iri (metadata, uuid);
+               if (region->link_uri && region->link_class) {
+                       tracker_resource_set_string (region_resource, "nfo:roiRefersTo", region->link_uri);
+               }
 
-                g_free (uuid);
-        }
+               tracker_resource_add_relation (resource, "nfo:hasRegionOfInterest", region_resource);
+       }
 
-        return TRUE;
+       return TRUE;
 }
diff --git a/src/libtracker-extract/tracker-xmp.h b/src/libtracker-extract/tracker-xmp.h
index ce8a2d4..3a3016d 100644
--- a/src/libtracker-extract/tracker-xmp.h
+++ b/src/libtracker-extract/tracker-xmp.h
@@ -171,16 +171,11 @@ TrackerXmpData *tracker_xmp_new           (const gchar          *buffer,
                                            gsize                 len,
                                            const gchar          *uri);
 void            tracker_xmp_free          (TrackerXmpData       *data);
-gboolean        tracker_xmp_apply         (TrackerSparqlBuilder *preupdate,
-                                           TrackerSparqlBuilder *metadata,
-                                           const gchar          *graph,
-                                           GString              *where,
-                                           const gchar          *uri,
-                                           TrackerXmpData       *data);
-gboolean        tracker_xmp_apply_regions (TrackerSparqlBuilder *preupdate,
-                                           TrackerSparqlBuilder *metadata,
-                                           const gchar          *graph,
-                                           TrackerXmpData       *data);
+
+gboolean        tracker_xmp_apply_to_resource         (TrackerResource *resource,
+                                                       TrackerXmpData  *data);
+gboolean        tracker_xmp_apply_regions_to_resource (TrackerResource *resource,
+                                                       TrackerXmpData  *data);
 
 #ifndef TRACKER_DISABLE_DEPRECATED
 
@@ -188,6 +183,7 @@ gboolean         tracker_xmp_read  (const gchar          *buffer,
                                     size_t                len,
                                     const gchar          *uri,
                                     TrackerXmpData       *data) G_GNUC_DEPRECATED;
+
 #endif /* TRACKER_DISABLE_DEPRECATED */
 
 G_END_DECLS
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index c6845c1..bf8e66d 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -213,7 +213,7 @@ tracker_resource_new (const char *identifier)
 {
        TrackerResource *resource;
 
-       resource = g_object_new (TRACKER_TYPE_RESOURCE, NULL,
+       resource = g_object_new (TRACKER_TYPE_RESOURCE,
                                 "identifier", identifier,
                                 NULL);
 
@@ -706,6 +706,12 @@ typedef struct {
 
 void generate_turtle (TrackerResource *resource, GenerateTurtleData *data);
 
+gboolean
+is_blank_node (const char *uri_or_curie_or_blank)
+{
+       return (strncmp(uri_or_curie_or_blank, "_:", 2) == 0);
+}
+
 void
 generate_nested_turtle_resource (TrackerResource    *resource,
                                  GenerateTurtleData *data)
@@ -749,50 +755,123 @@ generate_turtle_resources_foreach (gpointer key,
 }
 
 static void
-generate_turtle_value (const GValue       *value,
-                       GenerateTurtleData *data)
+generate_turtle_uri_value (const char              *uri_or_curie_or_blank,
+                           GString                 *string,
+                           TrackerNamespaceManager *all_namespaces,
+                           TrackerNamespaceManager *our_namespaces)
+{
+       /* The tracker_resource_set_uri() function accepts URIs
+        * (such as http://example.com/) and compact URIs (such as nie:DataObject),
+        * and blank node identifiers (_:0). The tracker_resource_set_identifier()
+        * function works the same.
+        *
+        * We could expand all CURIEs, but the generated Turtle or SPARQL will be
+        * clearer if we leave them be. We still need to attempt to expand them
+        * internally in order to know whether they need <> brackets around them.
+        */
+       if (is_blank_node (uri_or_curie_or_blank)) {
+               g_string_append (string, uri_or_curie_or_blank);
+       } else {
+               char *prefix = g_uri_parse_scheme (uri_or_curie_or_blank);
+
+               if (prefix && tracker_namespace_manager_has_prefix (all_namespaces, prefix)) {
+                       /* It's a compact URI and we know the prefix */
+                       if (our_namespaces != NULL) {
+                               maybe_intern_prefix_of_compact_uri (all_namespaces, our_namespaces, 
uri_or_curie_or_blank);
+                       };
+
+                       g_string_append (string, uri_or_curie_or_blank);
+               } else {
+                       /* It's a full URI (or something invalid, but we can't really tell that here) */
+                       g_string_append_printf (string, "<%s>", uri_or_curie_or_blank);
+               }
+       }
+}
+
+static void
+generate_turtle_value (const GValue            *value,
+                       GString                 *string,
+                       TrackerNamespaceManager *all_namespaces,
+                       TrackerNamespaceManager *our_namespaces)
 {
        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);
+               generate_turtle_uri_value (g_value_get_string (value),
+                                          string,
+                                          all_namespaces,
+                                          our_namespaces);
        } 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));
+               generate_turtle_uri_value (tracker_resource_get_identifier (relation),
+                                          string,
+                                          all_namespaces,
+                                          our_namespaces);
        } else if (type == G_TYPE_STRING) {
-               g_string_append_printf(data->string, "\"%s\"", g_value_get_string (value));
+               char *escaped = tracker_sparql_escape_string (g_value_get_string (value));
+               g_string_append_printf(string, "\"%s\"", escaped);
+               g_free (escaped);
+       } else if (type == G_TYPE_DATE) {
+               char date_string[256];
+               g_date_strftime (date_string, 256,
+                                "\"%Y-%m-%d%z\"^^<http://www.w3.org/2001/XMLSchema#date>",
+                                g_value_get_boxed (value));
+               g_string_append (string, date_string);
+       } else if (type == G_TYPE_DATE_TIME) {
+               char *datetime_string;
+               datetime_string = g_date_time_format (g_value_get_boxed (value),
+                                                     
"\"%Y-%m-%dT%H:%M:%s%z\"^^<http://www.w3.org/2001/XMLSchema#dateTime>");
+               g_string_append (string, datetime_string);
+               g_free (datetime_string);
+       } else if (type == G_TYPE_DOUBLE || type == G_TYPE_FLOAT) {
+               /* We can't use GValue transformations here; they're locale-dependent. */
+               char buffer[256];
+               g_ascii_dtostr (buffer, 255, g_value_get_double (value));
+               g_string_append (string, buffer);
        } 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));
+                       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_warning ("Cannot serialize value of type %s to Turtle/SPARQL",
+                                   G_VALUE_TYPE_NAME (value));
                }
                g_value_unset (&str_value);
        }
 }
 
 void
-generate_turtle_property (const char         *property,
-                          const GValue       *value,
-                          GenerateTurtleData *data)
+generate_turtle_property (const char              *property,
+                          const GValue            *value,
+                          GString                 *string,
+                          TrackerNamespaceManager *all_namespaces,
+                          TrackerNamespaceManager *our_namespaces)
 {
-       g_string_append (data->string, property);
-       g_string_append (data->string, " ");
+       if (strcmp (property, TRACKER_PREFIX_RDF "type") == 0 || strcmp (property, "rdf:type") == 0) {
+               g_string_append (string, "a");
+       } else {
+               g_string_append (string, property);
+       }
+
+       g_string_append (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, 0), data);
+                       generate_turtle_value (g_ptr_array_index (array, 0),
+                                              string,
+                                              all_namespaces,
+                                              our_namespaces);
                        for (i = 1; i < array->len; i++) {
-                               g_string_append (data->string, " , ");
-                               generate_turtle_value (g_ptr_array_index (array, i), data);
+                               g_string_append (string, " , ");
+                               generate_turtle_value (g_ptr_array_index (array, i),
+                                                      string,
+                                                      all_namespaces,
+                                                      our_namespaces);
                        }
                }
        } else {
-               generate_turtle_value (value, data);
+               generate_turtle_value (value, string, all_namespaces, our_namespaces);
        }
 }
 
@@ -809,12 +888,14 @@ generate_turtle (TrackerResource    *resource,
        /* First we recurse to any relations that aren't already in the done list */
        g_hash_table_foreach (priv->properties, generate_turtle_resources_foreach, data);
 
-       g_string_append_printf (data->string, "<%s> ", priv->identifier);
+       generate_turtle_uri_value (tracker_resource_get_identifier(resource),
+               data->string, data->all_namespaces, data->our_namespaces);
+       g_string_append (data->string, " ");
 
        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);
+                       generate_turtle_property (property, value, data->string, data->all_namespaces, 
data->our_namespaces);
 
                        maybe_intern_prefix_of_compact_uri (data->all_namespaces, data->our_namespaces, 
property);
 
@@ -851,15 +932,22 @@ char *
 tracker_resource_print_turtle (TrackerResource         *self,
                                TrackerNamespaceManager *namespaces)
 {
+       TrackerResourcePrivate *priv;
        GenerateTurtleData context;
        char *prefixes;
 
        g_return_val_if_fail (TRACKER_IS_RESOURCE (self), "");
 
+       priv = GET_PRIVATE (self);
+
        if (namespaces == NULL) {
                namespaces = tracker_namespace_manager_get_default ();
        }
 
+       if (g_hash_table_size (priv->properties) == 0) {
+               return g_strdup("");
+       }
+
        context.all_namespaces = namespaces;
        context.our_namespaces = tracker_namespace_manager_new ();
        context.string = g_string_new ("");
@@ -883,255 +971,173 @@ tracker_resource_print_turtle (TrackerResource         *self,
 
 typedef struct {
        TrackerNamespaceManager *namespaces;
-       TrackerSparqlBuilder *builder;
+       GString *string;
        const char *graph_id;
        GList *done_list;
-       GHashTable *overwrite_flags;
 } GenerateSparqlData;
 
-void generate_sparql_update (TrackerResource *resource, GenerateSparqlData *data);
+static void generate_sparql_deletes (TrackerResource *resource, GenerateSparqlData *data);
+static void generate_sparql_insert_pattern (TrackerResource *resource, GenerateSparqlData *data);
 
 static void
-generate_sparql_relations_foreach (gpointer key,
-                                   gpointer value_ptr,
-                                   gpointer user_data)
+generate_sparql_relation_deletes_foreach (gpointer key,
+                                          gpointer value_ptr,
+                                          gpointer user_data)
 {
        const char *property = key;
        const GValue *value = value_ptr;
        GenerateSparqlData *data = user_data;
-       GError *error = NULL;
 
        if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
                TrackerResource *relation = g_value_get_object (value);
 
                if (g_list_find_custom (data->done_list, relation, (GCompareFunc) tracker_resource_compare) 
== NULL) {
-                       generate_sparql_update (relation, data);
+                       generate_sparql_deletes (relation, data);
                        data->done_list = g_list_prepend (data->done_list, relation);
                }
        }
 }
 
-static char *
-variable_name_for_property (const char *property) {
-       return g_strcanon (g_strdup (property),
-                          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
-                          '_');
-}
-
 static void
-generate_sparql_deletes_foreach (gpointer key,
-                                 gpointer value_ptr,
-                                 gpointer user_data)
+generate_sparql_relation_inserts_foreach (gpointer key,
+                                          gpointer value_ptr,
+                                          gpointer user_data)
 {
        const char *property = key;
        const GValue *value = value_ptr;
        GenerateSparqlData *data = user_data;
 
-       /* Whether to generate the DELETE is based on whether set_value was ever
-        * called for this property. That's tracked in a hash table.
-        */
-       if (g_hash_table_lookup (data->overwrite_flags, property)) {
-               char *variable_name = variable_name_for_property (property);
-               tracker_sparql_builder_predicate (data->builder, property);
-               tracker_sparql_builder_object_variable (data->builder, variable_name);
-               g_free (variable_name);
-       }
-}
-
-static void
-generate_sparql_uri_value (const char         *uri_or_curie,
-                           GenerateSparqlData *data)
-{
-       /* The tracker_resource_set_uri() function accepts both URIs
-        * (such as http://example.com/) and compact URIs (such as nie:DataObject).
-        * We could expand them here, but since the tracker-store can understand them
-        * as-is we leave them be and the generated SPARQL is clearer as a result.
-        * We still need to attempt to expand them in order to know whether they need
-        * <> brackets around them.
-        */
-       char *prefix = g_uri_parse_scheme (uri_or_curie);
+       if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
+               TrackerResource *relation = g_value_get_object (value);
 
-       if (prefix && tracker_namespace_manager_has_prefix (data->namespaces, prefix)) {
-               /* It's a compact URI and we know the prefix */
-               tracker_sparql_builder_object (data->builder, uri_or_curie);
-       } else {
-               /* It's a full URI (or something invalid, but we can't really tell that here) */
-               tracker_sparql_builder_object_iri (data->builder, uri_or_curie);
+               if (g_list_find_custom (data->done_list, relation, (GCompareFunc) tracker_resource_compare) 
== NULL) {
+                       generate_sparql_insert_pattern (relation, data);
+                       data->done_list = g_list_prepend (data->done_list, relation);
+               }
        }
 }
 
-static void
-generate_sparql_value (const GValue       *value,
-                       GenerateSparqlData *data)
-{
-       TrackerSparqlBuilder *builder = data->builder;
-       GType type = G_VALUE_TYPE (value);
-       if (type == G_TYPE_BOOLEAN) {
-               tracker_sparql_builder_object_boolean (builder, g_value_get_boolean (value));
-       } else if (type == G_TYPE_DATE) {
-               /* tracker_sparql_builder_object_date() exists, but it requires a
-                * time_t, and GDate and GDateTime don't provide those conveniently.
-                */
-               char literal[256];
-               g_date_strftime (literal, 256,
-                                "\"%Y-%m-%d%z\"^^<http://www.w3.org/2001/XMLSchema#date>",
-                                g_value_get_boxed (value));
-               tracker_sparql_builder_object (builder, literal);
-       } else if (type == G_TYPE_DATE_TIME) {
-               char *literal;
-               literal = g_date_time_format (g_value_get_boxed (value),
-                                             
"\"%Y-%m-%dT%H:%M:%s%z\"^^<http://www.w3.org/2001/XMLSchema#dateTime>");
-               tracker_sparql_builder_object (builder, literal);
-               g_free (literal);
-       } else if (type == G_TYPE_DOUBLE) {
-               tracker_sparql_builder_object_double (builder, g_value_get_double (value));
-       } else if (type == G_TYPE_FLOAT) {
-               tracker_sparql_builder_object_double (builder, g_value_get_float (value));
-       } else if (type == G_TYPE_CHAR) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_schar (value));
-       } else if (type == G_TYPE_INT) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_int (value));
-       } else if (type == G_TYPE_INT64) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_int64 (value));
-       } else if (type == G_TYPE_LONG) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_long (value));
-       } else if (type == G_TYPE_UCHAR) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_uchar (value));
-       } else if (type == G_TYPE_UINT) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_uint (value));
-       } else if (type == G_TYPE_ULONG) {
-               tracker_sparql_builder_object_int64 (builder, g_value_get_ulong (value));
-       } else if (type == G_TYPE_UINT64) {
-               g_warning ("Cannot serialize uint64 types to SPARQL. Use int64.");
-               tracker_sparql_builder_object (builder, "null");
-       } else if (type == G_TYPE_STRING) {
-               tracker_sparql_builder_object_string (builder, g_value_get_string (value));
-       } else if (type == TRACKER_TYPE_URI) {
-               generate_sparql_uri_value (g_value_get_string (value), data);
-       } else if (type == TRACKER_TYPE_RESOURCE) {
-               TrackerResource *relation = TRACKER_RESOURCE (g_value_get_object (value));
-               tracker_sparql_builder_object_iri (builder, tracker_resource_get_identifier (relation));
-       } else {
-               g_warning ("Cannot serialize value of type %s to SPARQL", G_VALUE_TYPE_NAME (value));
-               tracker_sparql_builder_object (builder, "null");
-       }
+static char *
+variable_name_for_property (const char *property) {
+       return g_strcanon (g_strdup (property),
+                          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
+                          '_');
 }
 
 static void
-generate_sparql_inserts_foreach (gpointer key,
-                                 gpointer value_ptr,
-                                 gpointer user_data)
+generate_sparql_delete_pattern (TrackerResource     *resource,
+                                GHashTable          *overwrite_flags,
+                                GenerateSparqlData  *data)
 {
-       const char *property = key;
-       const GValue *value = value_ptr;
-       GenerateSparqlData *data = user_data;
-       char *full_property;
-
-       full_property = tracker_namespace_manager_expand_uri (data->namespaces, property);
+       TrackerResourcePrivate *priv = GET_PRIVATE (resource);
+       GHashTableIter iter;
+       const char *property;
+       const GValue *value;
+       gboolean had_property;
 
-       /* The caller should have already set rdf:type */
-       if (strcmp (full_property, TRACKER_PREFIX_RDF "type") == 0 || strcmp (property, "rdf:type") == 0) {
-               g_free (full_property);
-               return;
+       if (data->graph_id) {
+               g_string_append_printf (data->string, "GRAPH <%s> {\n", data->graph_id);
        }
 
-       tracker_sparql_builder_predicate (data->builder, property);
+       g_string_append (data->string, "  ");
+       generate_turtle_uri_value (priv->identifier, data->string, data->namespaces, NULL);
+       g_string_append (data->string, "\n    ");
 
-       g_free (full_property);
+       had_property = FALSE;
+       g_hash_table_iter_init (&iter, priv->properties);
+       while (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value)) {
+               /* Whether to generate the DELETE is based on whether set_value was ever
+               * called for this property. That's tracked in the overwrite_flags hash table.
+               */
+               if (g_hash_table_lookup (overwrite_flags, property)) {
+                       if (had_property) {
+                               g_string_append (data->string, " ;\n    ");
+                       }
 
-       if (G_VALUE_TYPE (value) == G_TYPE_PTR_ARRAY) {
-               g_ptr_array_foreach (g_value_get_boxed (value), (GFunc)generate_sparql_value, data);
-       } else {
-               generate_sparql_value (value, data);
+                       char *variable_name = variable_name_for_property (property);
+                       g_string_append_printf (data->string, "  %s ?%s", property, variable_name);
+                       g_free (variable_name);
+
+                       had_property = TRUE;
+               }
+       }
+
+       if (data->graph_id) {
+               g_string_append (data->string, " }");
        }
 }
 
 void
-generate_sparql_update (TrackerResource    *resource,
-                        GenerateSparqlData *data)
+generate_sparql_deletes (TrackerResource    *resource,
+                         GenerateSparqlData *data)
 {
        TrackerResourcePrivate *priv = GET_PRIVATE (resource);
-       TrackerSparqlBuilder *builder = data->builder;
-       GValue *type_value;
 
-       if (!priv->identifier) {
-               g_warning ("Main resource must have an identifier.");
-               return;
-       }
-
-       g_return_if_fail (tracker_sparql_builder_get_state (builder) == TRACKER_SPARQL_BUILDER_STATE_UPDATE);
-
-       /* Delete the existing data. If we don't do this, we may get constraint
-        * violations due to trying to add a second value to a single-valued
-        * property, and we may get old metadata hanging around.
-        *
-        * We have to generate a rather awkward query here, like:
+       /* We have to generate a rather awkward query here, like:
         *
         *     DELETE { pattern } WHERE { pattern }
         *
         * It would be better if we could use "DELETE DATA { pattern }". This is
         * allowed in SPARQL update 1.1, but not yet supported by Tracker's store.
         */
-       data->overwrite_flags = priv->overwrite;
-
-       tracker_sparql_builder_delete_open (builder, NULL);
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_open (builder, data->graph_id);
-       }
-       tracker_sparql_builder_subject_iri (builder, priv->identifier);
-       g_hash_table_foreach (priv->properties, generate_sparql_deletes_foreach, data);
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_close (builder);
-       }
-       tracker_sparql_builder_delete_close (builder);
-
-       tracker_sparql_builder_where_open (builder);
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_open (builder, data->graph_id);
-       }
-       tracker_sparql_builder_subject_iri (builder, priv->identifier);
-       g_hash_table_foreach (priv->properties, generate_sparql_deletes_foreach, data);
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_close (builder);
+       if (! is_blank_node (priv->identifier)) {
+               if (g_hash_table_size (priv->overwrite) > 0) {
+                       g_string_append (data->string, "DELETE {\n");
+                       generate_sparql_delete_pattern (resource, priv->overwrite, data);
+                       g_string_append (data->string, "\n}\nWHERE {\n");
+                       generate_sparql_delete_pattern (resource, priv->overwrite, data);
+                       g_string_append (data->string, "\n}\n");
+               }
        }
-       tracker_sparql_builder_where_close (builder);
 
        /* Now emit any sub-resources. */
-       g_hash_table_foreach (priv->properties, generate_sparql_relations_foreach, data);
+       g_hash_table_foreach (priv->properties, generate_sparql_relation_deletes_foreach, data);
+}
 
-       /* Finally insert the rest of the data */
+static void
+generate_sparql_insert_pattern (TrackerResource    *resource,
+                                GenerateSparqlData *data)
+{
+       TrackerResourcePrivate *priv = GET_PRIVATE (resource);
+       GHashTableIter iter;
+       const char *property;
+       char *full_property;
+       const GValue *value;
+       gboolean had_property = FALSE;
 
-       /* Passing the graph directly to insert_open causes it to generate a
-        * non-standard 'INSERT INTO <graph>' statement, while calling graph_open
-        * separately causes it to generate INSERT { GRAPH { .. } }. See
-        * <https://bugzilla.gnome.org/show_bug.cgi?id=658838>.
-        */
-       tracker_sparql_builder_insert_open (builder, NULL);
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_open (builder, data->graph_id);
-       }
+       /* First, emit any sub-resources. */
+       g_hash_table_foreach (priv->properties, generate_sparql_relation_inserts_foreach, data);
 
-       tracker_sparql_builder_subject_iri (builder, priv->identifier);
+       generate_turtle_uri_value (priv->identifier, data->string, data->namespaces, NULL);
+       g_string_append_printf (data->string, " ");
 
        /* rdf:type needs to be first, otherwise you'll see 'subject x is not in domain y'
         * errors for the properties you try to set.
         */
-       type_value = g_hash_table_lookup (priv->properties, "rdf:type");
-       if (type_value != NULL) {
-               tracker_sparql_builder_predicate (builder, "a");
-               if (G_VALUE_TYPE (type_value) == G_TYPE_PTR_ARRAY) {
-                       g_ptr_array_foreach (g_value_get_boxed (type_value), (GFunc)generate_sparql_value, 
data);
-               } else {
-                       generate_sparql_value (type_value, data);
-               }
+       value = g_hash_table_lookup (priv->properties, "rdf:type");
+       if (value != NULL) {
+               generate_turtle_property ("a", value, data->string, data->namespaces, NULL);
+               had_property = TRUE;
        }
 
-       g_hash_table_foreach (priv->properties, generate_sparql_inserts_foreach, data);
+       g_hash_table_iter_init (&iter, priv->properties);
+       while (g_hash_table_iter_next (&iter, (gpointer *)&property, (gpointer *)&value)) {
+               full_property = tracker_namespace_manager_expand_uri (data->namespaces, property);
 
-       if (data->graph_id) {
-               tracker_sparql_builder_graph_close (builder);
+               if (strcmp (full_property, TRACKER_PREFIX_RDF "type") != 0 && strcmp (property, "rdf:type") 
!= 0) {
+                       if (had_property) {
+                               g_string_append (data->string, " ; \n  ");
+                       }
+
+                       generate_turtle_property (property, value, data->string, data->namespaces, NULL);
+
+                       had_property = TRUE;
+               }
+
+               g_free (full_property);
        }
-       tracker_sparql_builder_insert_close (builder);
+
+       g_string_append (data->string, " .\n");
 }
 
 /**
@@ -1159,17 +1165,24 @@ tracker_resource_print_sparql_update (TrackerResource         *resource,
                                       TrackerNamespaceManager *namespaces,
                                       const char              *graph_id)
 {
+       TrackerResourcePrivate *priv;
        GenerateSparqlData context;
        char *result;
 
        g_return_val_if_fail (TRACKER_IS_RESOURCE (resource), "");
 
+       priv = GET_PRIVATE(resource);
+
        if (namespaces == NULL) {
                namespaces = tracker_namespace_manager_get_default ();
        }
 
+       if (g_hash_table_size (priv->properties) == 0) {
+               return g_strdup("");
+       }
+
        context.namespaces = namespaces;
-       context.builder = tracker_sparql_builder_new_update ();
+       context.string = g_string_new (NULL);
        context.graph_id = graph_id;
 
        /* Resources can be recursive, and may have repeated or even cyclic
@@ -1177,15 +1190,27 @@ tracker_resource_print_sparql_update (TrackerResource         *resource,
         */
        context.done_list = NULL;
 
-       generate_sparql_update (resource, &context);
+       /* Delete the existing data. If we don't do this, we may get constraint
+        * violations due to trying to add a second value to a single-valued
+        * property, and we may get old metadata hanging around.
+        */
+       generate_sparql_deletes (resource, &context);
 
        g_list_free (context.done_list);
+       context.done_list = NULL;
 
-       /* We could save a memcpy here by returning the SparqlBuilder instead, but
-        * this way we are free to remove the TrackerSparqlBuilder code altogether
-        * in future without having to change the public API of TrackerResource.
-        */
-       result = g_strdup (tracker_sparql_builder_get_result (context.builder));
-       g_object_unref (context.builder);
-       return result;
+       /* Finally insert the data */
+       g_string_append (context.string, "INSERT {\n");
+       if (graph_id) {
+               g_string_append_printf (context.string, "GRAPH <%s> {\n", graph_id);
+       }
+
+       generate_sparql_insert_pattern (resource, &context);
+
+       if (graph_id) {
+               g_string_append (context.string, "}\n");
+       }
+       g_string_append (context.string, "}\n");
+
+       return g_string_free (context.string, FALSE);
 }
diff --git a/src/tracker-extract/tracker-extract-abw.c b/src/tracker-extract/tracker-extract-abw.c
index 621e534..d8172af 100644
--- a/src/tracker-extract/tracker-extract-abw.c
+++ b/src/tracker-extract/tracker-extract-abw.c
@@ -47,8 +47,7 @@ typedef enum {
 } AbwParserTag;
 
 struct AbwParserData {
-       TrackerSparqlBuilder *metadata;
-       TrackerSparqlBuilder *preupdate;
+       TrackerResource *resource;
        GString *content;
        gchar *uri;
 
@@ -109,8 +108,7 @@ abw_parser_text (GMarkupParseContext *context,
                                   str, data->uri);
                } else {
                        data->has_title = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, str);
+                       tracker_resource_set_string (data->resource, "nie:title", str);
                }
                break;
        case ABW_PARSER_TAG_SUBJECT:
@@ -119,29 +117,24 @@ abw_parser_text (GMarkupParseContext *context,
                                   str, data->uri);
                } else {
                        data->has_subject = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:subject");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, str);
+                       tracker_resource_set_string (data->resource, "nie:subject", str);
                }
                break;
-       case ABW_PARSER_TAG_CREATOR:
-               tracker_sparql_builder_predicate (data->metadata, "nco:creator");
+       case ABW_PARSER_TAG_CREATOR: {
+               TrackerResource *creator;
+               creator = tracker_extract_new_contact (str);
+               tracker_resource_set_relation (data->resource, "nco:creator", creator);
+               g_object_unref (creator);
 
-               tracker_sparql_builder_object_blank_open (data->metadata);
-               tracker_sparql_builder_predicate (data->metadata, "a");
-               tracker_sparql_builder_object (data->metadata, "nco:Contact");
-
-               tracker_sparql_builder_predicate (data->metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (data->metadata, str);
-               tracker_sparql_builder_object_blank_close (data->metadata);
                break;
+       }
        case ABW_PARSER_TAG_DESCRIPTION:
                if (data->has_comment) {
                        g_warning ("Avoiding additional comment (%s) in Abiword document '%s'",
                                   str, data->uri);
                } else {
                        data->has_comment = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:comment");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, str);
+                       tracker_resource_set_string (data->resource, "nie:comment", str);
                }
                break;
        case ABW_PARSER_TAG_GENERATOR:
@@ -150,8 +143,7 @@ abw_parser_text (GMarkupParseContext *context,
                                   str, data->uri);
                } else {
                        data->has_generator = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:generator");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, str);
+                       tracker_resource_set_string (data->resource, "nie:generator", str);
                }
                break;
        case ABW_PARSER_TAG_KEYWORDS:
@@ -160,8 +152,7 @@ abw_parser_text (GMarkupParseContext *context,
 
                for (keyword = strtok_r (str, ",; ", &lasts); keyword;
                     keyword = strtok_r (NULL, ",; ", &lasts)) {
-                       tracker_sparql_builder_predicate (data->metadata, "nie:keyword");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, keyword);
+                       tracker_resource_add_string (data->resource, "nie:keyword", keyword);
                }
        }
                break;
@@ -191,7 +182,6 @@ static GMarkupParser parser = {
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *preupdate, *metadata;
        int fd;
        gchar *filename, *contents;
        gboolean retval = FALSE;
@@ -199,9 +189,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        gsize len;
        struct stat st;
 
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-
        f = tracker_extract_info_get_file (info);
        filename = g_file_get_path (f);
 
@@ -248,11 +235,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                AbwParserData data = { 0 };
 
                data.uri = g_file_get_uri (f);
-               data.metadata = metadata;
-               data.preupdate = preupdate;
+               data.resource = tracker_resource_new (NULL);
 
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nfo:Document");
+               tracker_resource_add_uri (data.resource, "rdf:type", "nfo:Document");
 
                context = g_markup_parse_context_new (&parser, 0, &data, NULL);
                g_markup_parse_context_parse (context, contents, len, &error);
@@ -262,8 +247,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                        g_error_free (error);
                } else {
                        if (data.content) {
-                               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-                               tracker_sparql_builder_object_unvalidated (metadata, data.content->str);
+                               tracker_resource_set_string (data.resource, "nie:plainTextContent", 
data.content->str);
                                g_string_free (data.content, TRUE);
                        }
 
@@ -272,8 +256,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
                g_markup_parse_context_free (context);
                g_free (data.uri);
-       }
 
+               tracker_extract_info_set_resource (info, data.resource);
+               g_object_unref (data.resource);
+       }
 
        if (contents) {
                munmap (contents, len);
diff --git a/src/tracker-extract/tracker-extract-bmp.c b/src/tracker-extract/tracker-extract-bmp.c
index 1f3e41e..be7dc66 100644
--- a/src/tracker-extract/tracker-extract-bmp.c
+++ b/src/tracker-extract/tracker-extract-bmp.c
@@ -105,14 +105,12 @@ get_img_resolution (const GFile *file,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *image;
        goffset size;
        gchar *filename;
        GFile *file;
        gint64 width = 0, height = 0;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
-
        file = tracker_extract_info_get_file (info);
        if (!file) {
                return FALSE;
@@ -127,21 +125,21 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_object (metadata, "nmm:Photo");
+       image = tracker_resource_new (NULL);
+       tracker_resource_add_uri (image, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (image, "rdf:type", "nmm:Photo");
 
        if (get_img_resolution (file, &width, &height)) {
                if (width > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:width");
-                       tracker_sparql_builder_object_int64 (metadata, width);
+                       tracker_resource_set_int64 (image, "nfo:width", width);
                }
 
                if (height > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:height");
-                       tracker_sparql_builder_object_int64 (metadata, height);
+                       tracker_resource_set_int64 (image, "nfo:height", height);
                }
        }
 
+       tracker_extract_info_set_resource (info, image);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-decorator.c b/src/tracker-extract/tracker-extract-decorator.c
index e011a92..6376187 100644
--- a/src/tracker-extract/tracker-extract-decorator.c
+++ b/src/tracker-extract/tracker-extract-decorator.c
@@ -146,60 +146,34 @@ decorator_save_info (TrackerSparqlBuilder    *sparql,
                      TrackerDecoratorInfo    *decorator_info,
                      TrackerExtractInfo      *info)
 {
-       const gchar *urn, *result, *where;
-       TrackerSparqlBuilder *builder;
-       gchar *str;
-
-       urn = tracker_decorator_info_get_urn (decorator_info);
-
-       tracker_sparql_builder_insert_open (sparql, NULL);
-       tracker_sparql_builder_graph_open (sparql, TRACKER_OWN_GRAPH_URN);
-
-       /* Set tracker-extract data source */
-       tracker_sparql_builder_subject_iri (sparql, urn);
-       tracker_sparql_builder_predicate (sparql, "nie:dataSource");
-       tracker_sparql_builder_object_iri (sparql,
-                                          tracker_decorator_get_data_source (TRACKER_DECORATOR (decorator)));
-
-       builder = tracker_extract_info_get_metadata_builder (info);
-
-       if (tracker_sparql_builder_get_length (builder) > 0) {
-               /* Add extracted metadata */
-               str = g_strdup_printf ("<%s>", urn);
-               tracker_sparql_builder_append (sparql, str);
-               g_free (str);
-
-               result = tracker_sparql_builder_get_result (builder);
-               tracker_sparql_builder_append (sparql, result);
-
-               /* Close graph and insert statement, insert where clause */
-               tracker_sparql_builder_graph_close (sparql);
-               tracker_sparql_builder_insert_close (sparql);
-
-               where = tracker_extract_info_get_where_clause (info);
-
-               if (where && *where) {
-                       tracker_sparql_builder_where_open (sparql);
-                       tracker_sparql_builder_append (sparql, where);
-                       tracker_sparql_builder_where_close (sparql);
-               }
-       } else {
-               tracker_sparql_builder_graph_close (sparql);
-               tracker_sparql_builder_insert_close (sparql);
+       const gchar *urn;
+       TrackerResource *resource = NULL;
+       gchar *sparql_command;
+
+       g_set_object (&resource, tracker_extract_info_get_resource (info));
+
+       if (resource == NULL) {
+               g_message ("Extract module returned no resource for %s",
+                          tracker_decorator_info_get_url (info));
+               /* We must still insert something into the store so that the correct
+                * nie:dataSource triple get inserted. Otherwise, tracker-extract will
+                * try to re-extract this file every time it starts.
+                */
+               resource = tracker_resource_new (NULL);
        }
 
-       /* Prepend/append pre/postupdate chunks */
-       builder = tracker_extract_info_get_preupdate_builder (info);
-       result = tracker_sparql_builder_get_result (builder);
+       urn = tracker_decorator_info_get_urn (decorator_info);
 
-       if (result && *result)
-               tracker_sparql_builder_prepend (sparql, result);
+       tracker_resource_set_identifier (resource, urn);
+       tracker_resource_set_uri (resource, "nie:dataSource",
+               tracker_decorator_get_data_source (TRACKER_DECORATOR (decorator)));
 
-       builder = tracker_extract_info_get_postupdate_builder (info);
-       result = tracker_sparql_builder_get_result (builder);
+       sparql_command = tracker_resource_print_sparql_update (
+               resource, NULL, TRACKER_OWN_GRAPH_URN);
+       tracker_sparql_builder_append (sparql, sparql_command);
 
-       if (result && *result)
-               tracker_sparql_builder_append (sparql, result);
+       g_object_unref (resource);
+       g_free (sparql_command);
 }
 
 static void
@@ -310,8 +284,6 @@ decorator_next_item_cb (TrackerDecorator *decorator,
        tracker_extract_file (priv->extractor,
                              tracker_decorator_info_get_url (info),
                              tracker_decorator_info_get_mimetype (info),
-                             TRACKER_OWN_GRAPH_URN,
-                             tracker_decorator_info_get_urn (info),
                              g_task_get_cancellable (task),
                              (GAsyncReadyCallback) get_metadata_cb, data);
 }
diff --git a/src/tracker-extract/tracker-extract-dvi.c b/src/tracker-extract/tracker-extract-dvi.c
index 355abdd..48c6aef 100644
--- a/src/tracker-extract/tracker-extract-dvi.c
+++ b/src/tracker-extract/tracker-extract-dvi.c
@@ -214,12 +214,11 @@ error:
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *resource;
        GFile *file;
        gchar *filename;
        DviContext *context;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
 
@@ -231,18 +230,20 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+       resource = tracker_resource_new (NULL);
 
-       tracker_sparql_builder_predicate (metadata, "nfo:pageCount");
-       tracker_sparql_builder_object_int64 (metadata, context->npages);
+       tracker_resource_add_uri (resource, "rdf:type", "nfo:PaginatedTextDocument");
+
+       tracker_resource_set_int64 (resource, "nfo:pageCount", context->npages);
 
        if (context->fileid) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, context->fileid);
+               tracker_resource_set_string (resource, "nie:comment", context->fileid);
        }
 
        mdvi_destroy_context (context);
 
+       tracker_extract_info_set_resource (info, resource);
+       g_object_unref (resource);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-epub.c b/src/tracker-extract/tracker-extract-epub.c
index fef8012..4f7b5cf 100644
--- a/src/tracker-extract/tracker-extract-epub.c
+++ b/src/tracker-extract/tracker-extract-epub.c
@@ -46,9 +46,7 @@ typedef enum {
 } OPFTagType;
 
 typedef struct {
-       gchar *graph;
-       TrackerSparqlBuilder *preupdate;
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *resource;
        gchar *uri;
 
        OPFTagType element;
@@ -71,21 +69,13 @@ typedef struct {
 } OPFContentData;
 
 static inline OPFData *
-opf_data_new (TrackerExtractInfo *info)
+opf_data_new (const char *uri,
+              TrackerResource *resource)
 {
        OPFData *data = g_slice_new0 (OPFData);
-       TrackerSparqlBuilder *builder;
-       GFile *file;
-
-       file = tracker_extract_info_get_file (info);
-       builder = tracker_extract_info_get_preupdate_builder (info);
-       data->preupdate = g_object_ref (builder);
 
-       builder = tracker_extract_info_get_metadata_builder (info);
-       data->metadata = g_object_ref (builder);
-
-       data->graph = g_strdup (tracker_extract_info_get_graph (info));
-       data->uri = g_file_get_uri (file);
+       data->uri = g_strdup (uri);
+       data->resource = g_object_ref (resource);
 
        return data;
 }
@@ -113,17 +103,9 @@ opf_data_free (OPFData *data)
        g_list_foreach (data->pages, (GFunc) g_free, NULL);
        g_list_free (data->pages);
 
-       g_free (data->graph);
+       g_object_unref (data->resource);
        g_free (data->uri);
 
-       if (data->metadata) {
-               g_object_unref (data->metadata);
-       }
-
-       if (data->preupdate) {
-               g_object_unref (data->preupdate);
-       }
-
        g_slice_free (OPFData, data);
 }
 
@@ -289,22 +271,22 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                        g_warning ("Avoiding additional publisher (%s) in EPUB '%s'",
                                   text, data->uri);
                } else {
-                       data->has_publisher = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nco:publisher");
+                       TrackerResource *publisher;
+
+                       publisher = tracker_resource_new (NULL);
+                       tracker_resource_set_uri (publisher, "rdf:type", "nco:Contact");
+                       tracker_resource_set_string (publisher, "nco:fullname", text);
 
-                       tracker_sparql_builder_object_blank_open (data->metadata);
-                       tracker_sparql_builder_predicate (data->metadata, "a");
-                       tracker_sparql_builder_object (data->metadata, "nco:Contact");
+                       tracker_resource_set_relation (data->resource, "nco:publisher", publisher);
 
-                       tracker_sparql_builder_predicate (data->metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
-                       tracker_sparql_builder_object_blank_close (data->metadata);
+                       data->has_publisher = TRUE;
                }
                break;
        case OPF_TAG_TYPE_AUTHOR:
        case OPF_TAG_TYPE_EDITOR:
        case OPF_TAG_TYPE_ILLUSTRATOR:
        case OPF_TAG_TYPE_CONTRIBUTOR: {
+               TrackerResource *contact, *artist;
                gchar *fname, *gname, *oname;
                const gchar *fullname = NULL;
                gchar *role_uri = NULL;
@@ -411,56 +393,37 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                }
 
                if (role_uri) {
-                       tracker_sparql_builder_insert_open (data->preupdate, NULL);
-                       if (data->graph) {
-                               tracker_sparql_builder_graph_open (data->preupdate, data->graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (data->preupdate, role_uri);
-                       tracker_sparql_builder_predicate (data->preupdate, "a");
-                       tracker_sparql_builder_object (data->preupdate, "nmm:Artist");
-                       tracker_sparql_builder_predicate (data->preupdate, "nmm:artistName");
-                       tracker_sparql_builder_object_unvalidated (data->preupdate, fullname);
-
-                       if (data->graph) {
-                               tracker_sparql_builder_graph_close (data->preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (data->preupdate);
+                       artist = tracker_resource_new (role_uri);
+                       tracker_resource_set_uri (artist, "rdf:type", "nmm:Artist");
+                       tracker_resource_set_string (artist, "nmm:artistName", fullname);
                }
 
                /* Creator contact details */
-               tracker_sparql_builder_predicate (data->metadata, "nco:creator");
-               tracker_sparql_builder_object_blank_open (data->metadata);
-               tracker_sparql_builder_predicate (data->metadata, "a");
-               tracker_sparql_builder_object (data->metadata, "nco:PersonContact");
-               tracker_sparql_builder_predicate (data->metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (data->metadata, fullname);
+               contact = tracker_resource_new (NULL);
+               tracker_resource_set_uri (contact, "rdf:type",  "nco:PersonContact");
+               tracker_resource_set_string (contact, "nco:fullname", fullname);
 
                if (fname) {
-                       tracker_sparql_builder_predicate (data->metadata, "nco:nameFamily");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, fname);
+                       tracker_resource_set_string (contact, "nco:nameFamily", fname);
                        g_free (fname);
                }
 
                if (gname) {
-                       tracker_sparql_builder_predicate (data->metadata, "nco:nameGiven");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, gname);
+                       tracker_resource_set_string (contact, "nco:nameGiven", gname);
                        g_free (gname);
                }
 
                if (oname) {
-                       tracker_sparql_builder_predicate (data->metadata, "nco:nameAdditional");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, oname);
+                       tracker_resource_set_string (contact, "nco:nameAdditional", oname);
                        g_free (oname);
                }
 
                if (role_uri) {
-                       tracker_sparql_builder_predicate (data->metadata, role_str);
-                       tracker_sparql_builder_object_iri (data->metadata, role_uri);
+                       tracker_resource_set_relation (contact, role_str, artist);
                        g_free (role_uri);
                }
 
-               tracker_sparql_builder_object_blank_close (data->metadata);
+               tracker_resource_set_relation (data->resource, "nco:creator", contact);
 
                break;
        }
@@ -470,8 +433,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                                   text, data->uri);
                } else {
                        data->has_title = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
+                       tracker_resource_set_string (data->resource, "nie:title", text);
                }
                break;
        case OPF_TAG_TYPE_CREATED: {
@@ -483,8 +445,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
 
                        if (date) {
                                data->has_content_created = TRUE;
-                               tracker_sparql_builder_predicate (data->metadata, "nie:contentCreated");
-                               tracker_sparql_builder_object_unvalidated (data->metadata, date);
+                               tracker_resource_set_string (data->resource, "nie:contentCreated", date);
                                g_free (date);
                        } else {
                                g_warning ("Could not parse creation time (%s) in EPUB '%s'",
@@ -499,8 +460,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                                   text, data->uri);
                } else {
                        data->has_language = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:language");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
+                       tracker_resource_set_string (data->resource, "nie:language", text);
                }
                break;
        case OPF_TAG_TYPE_SUBJECT:
@@ -509,8 +469,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                                   text, data->uri);
                } else {
                        data->has_subject = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:subject");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
+                       tracker_resource_set_string (data->resource, "nie:subject", text);
                }
                break;
        case OPF_TAG_TYPE_DESCRIPTION:
@@ -519,8 +478,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                                   text, data->uri);
                } else {
                        data->has_description = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:description");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
+                       tracker_resource_set_string (data->resource, "nie:description", text);
                }
                break;
        case OPF_TAG_TYPE_UUID:
@@ -530,8 +488,7 @@ opf_xml_text_handler (GMarkupParseContext   *context,
                                   text, data->uri);
                } else {
                        data->has_identifier = TRUE;
-                       tracker_sparql_builder_predicate (data->metadata, "nie:identifier");
-                       tracker_sparql_builder_object_unvalidated (data->metadata, text);
+                       tracker_resource_set_string (data->resource, "nie:identifier", text);
                }
                break;
        /* case OPF_TAG_TYPE_RATING: */
@@ -650,11 +607,11 @@ extract_opf_contents (const gchar *uri,
        return g_string_free (content_data.contents, FALSE);
 }
 
-static gboolean
+static TrackerResource *
 extract_opf (const gchar          *uri,
-             const gchar          *opf_path,
-             TrackerExtractInfo   *info)
+             const gchar          *opf_path)
 {
+       TrackerResource *ebook;
        GMarkupParseContext *context;
        OPFData *data = NULL;
        GError *error = NULL;
@@ -668,10 +625,10 @@ extract_opf (const gchar          *uri,
 
        g_debug ("Extracting OPF file contents from EPUB '%s'", uri);
 
-       data = opf_data_new (info);
+       ebook = tracker_resource_new (NULL);
+       tracker_resource_add_uri (ebook, "rdf:type", "nfo:EBook");
 
-       tracker_sparql_builder_predicate (data->metadata, "a");
-       tracker_sparql_builder_object (data->metadata, "nfo:EBook");
+       data = opf_data_new (uri, ebook);
 
        /* Create parsing context */
        context = g_markup_parse_context_new (&opf_parser, 0, data, NULL);
@@ -687,7 +644,8 @@ extract_opf (const gchar          *uri,
                           (error) ? error->message : "No error provided");
                g_error_free (error);
                opf_data_free (data);
-               return FALSE;
+               g_object_unref (ebook);
+               return NULL;
        }
 
        dirname = g_path_get_dirname (opf_path);
@@ -695,19 +653,19 @@ extract_opf (const gchar          *uri,
        g_free (dirname);
 
        if (contents && *contents) {
-               tracker_sparql_builder_predicate (data->metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (data->metadata, contents);
+               tracker_resource_set_string (ebook, "nie:plainTextContent", contents);
        }
 
        opf_data_free (data);
        g_free (contents);
 
-       return TRUE;
+       return ebook;
 }
 
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
+       TrackerResource *ebook;
        gchar *opf_path, *uri;
        GFile *file;
 
@@ -721,9 +679,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       extract_opf (uri, opf_path, info);
+       ebook = extract_opf (uri, opf_path);
        g_free (opf_path);
        g_free (uri);
 
+       tracker_extract_info_set_resource (info, ebook);
+       g_object_unref (ebook);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-flac.c b/src/tracker-extract/tracker-extract-flac.c
index ba231b8..5185b4b 100644
--- a/src/tracker-extract/tracker-extract-flac.c
+++ b/src/tracker-extract/tracker-extract-flac.c
@@ -142,13 +142,12 @@ parse_vorbis_comments (FLAC__StreamMetadata_VorbisComment *comment,
 }
 
 static void
-add_tuple (TrackerSparqlBuilder *metadata,
-           const char           *predicate,
-           const char           *object)
+add_tuple (TrackerResource *metadata,
+           const char      *predicate,
+           const char      *object)
 {
        if (object) {
-               tracker_sparql_builder_predicate (metadata, predicate);
-               tracker_sparql_builder_object_unvalidated (metadata, object);
+               tracker_resource_set_string (metadata, predicate, object);
        }
 }
 
@@ -159,16 +158,11 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        FLAC__StreamMetadata *stream = NULL, *vorbis, *picture;
        FLAC__bool success;
        FlacData fd = { 0 };
-       TrackerSparqlBuilder *preupdate, *metadata;
-       gchar *filename, *uri, *artist_uri = NULL, *album_uri = NULL;
+       TrackerResource *metadata, *artist, *album_disc, *album, *album_artist;
+       gchar *filename, *uri;
        const gchar *creator;
        GFile *file;
        goffset size;
-       const gchar *graph;
-
-       graph = tracker_extract_info_get_graph (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
 
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
@@ -214,209 +208,55 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                }
        } while (FLAC__metadata_simple_iterator_next (iter));
 
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:MusicPiece");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Audio");
+
        creator = tracker_coalesce_strip (3, fd.artist, fd.albumartist,
                                          fd.performer);
 
        if (creator) {
-               artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", creator);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               artist = tracker_extract_new_artist (creator);
 
-               tracker_sparql_builder_subject_iri (preupdate, artist_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, creator);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               tracker_resource_set_relation (metadata, "nmm:performer", artist);
 
+               g_object_unref (artist);
        }
 
        if (fd.album) {
-                if (fd.albumartist) {
-                        album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s:%s", fd.album, 
fd.albumartist);
-                } else {
-                        album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", fd.album);
-                }
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, album_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum");
-               /* FIXME: nmm:albumTitle is now deprecated
-                * tracker_sparql_builder_predicate (preupdate, "nie:title");
-                */
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle");
-               tracker_sparql_builder_object_unvalidated (preupdate, fd.album);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
+               if (fd.albumartist) {
+                       album_artist = tracker_extract_new_artist (fd.albumartist);
+               } else {
+                       album_artist = NULL;
                }
-               tracker_sparql_builder_insert_close (preupdate);
 
-               if (fd.trackcount) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
+               album_disc = tracker_extract_new_music_album_disc (fd.album,
+                                                                  album_artist,
+                                                                  fd.discno ? atoi(fd.discno) : 1);
 
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_unvalidated (preupdate, fd.trackcount);
+               album = tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum");
 
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
+               if (fd.trackcount) {
+                       tracker_resource_set_string (album, "nmm:albumTrackCount", fd.trackcount);
                }
 
                if (fd.albumgain) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_double (preupdate, atof (fd.albumgain));
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
+                       tracker_resource_set_double (album, "nmm:albumGain", atof (fd.albumgain));
                }
 
                if (fd.albumpeakgain) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_double (preupdate, atof (fd.albumpeakgain));
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-       }
-
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
-       tracker_sparql_builder_object (metadata, "nfo:Audio");
-
-       add_tuple (metadata, "nmm:performer", artist_uri);
-       g_free (artist_uri);
-
-       add_tuple (metadata, "nmm:musicAlbum", album_uri);
-
-       tracker_guarantee_title_from_file (metadata, "nie:title", fd.title, uri, NULL);
-       add_tuple (metadata, "nmm:trackNumber", fd.tracknumber);
-
-       if (fd.album && album_uri) {
-               gchar *album_disc_uri;
-                if (fd.albumartist) {
-                        album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:%s:Disc%d",
-                                                                           fd.album, fd.albumartist,
-                                                                           fd.discno ? atoi(fd.discno) : 1);
-                } else {
-                        album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
-                                                                           fd.album,
-                                                                           fd.discno ? atoi(fd.discno) : 1);
-                }
-
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
+                       tracker_resource_set_double (album, "nmm:albumPeakGain", atof (fd.albumpeakgain));
                }
 
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc");
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_int64 (preupdate, fd.discno ? atoi (fd.discno) : 1);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_iri (preupdate, album_uri);
+               tracker_resource_set_relation (metadata, "nmm:musicAlbum", album);
+               tracker_resource_set_relation (metadata, "nmm:musicAlbumDisc", album_disc);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc");
-               tracker_sparql_builder_object_iri (metadata, album_disc_uri);
-
-               g_free (album_disc_uri);
+               g_object_unref (album_disc);
+               g_object_unref (album_artist);
        }
 
-       g_free (album_uri);
+       tracker_guarantee_resource_title_from_file (metadata, "nie:title", fd.title, uri, NULL);
+       add_tuple (metadata, "nmm:trackNumber", fd.tracknumber);
 
        /* FIXME: Trackgain/Trackpeakgain: commented out in vorbis */
 
@@ -428,36 +268,18 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        add_tuple (metadata, "nie:license", fd.license);
 
        if (fd.publisher) {
-               tracker_sparql_builder_predicate (metadata, "dc:publisher");
+               TrackerResource *publisher = tracker_extract_new_contact (fd.publisher);
 
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
+               tracker_resource_set_relation (metadata, "dc:publisher", publisher);
 
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata,
-                                                          fd.publisher);
-               tracker_sparql_builder_object_blank_close (metadata);
+               g_object_unref (publisher);
        }
 
        if (stream) {
-               tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
-               tracker_sparql_builder_object_int64 (metadata,
-                                                    stream->data.stream_info.sample_rate);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:channels");
-               tracker_sparql_builder_object_int64 (metadata,
-                                                    stream->data.stream_info.channels);
-
-               tracker_sparql_builder_predicate (metadata,
-                                                 "nfo:averageBitrate");
-               tracker_sparql_builder_object_int64 (metadata,
-                                                    stream->data.stream_info.bits_per_sample);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:duration");
-               tracker_sparql_builder_object_int64 (metadata,
-                                                    stream->data.stream_info.total_samples /
-                                                    stream->data.stream_info.sample_rate);
+               tracker_resource_set_int64 (metadata, "nfo:sampleRate", stream->data.stream_info.sample_rate);
+               tracker_resource_set_int64 (metadata, "nfo:channels", stream->data.stream_info.channels);
+               tracker_resource_set_int64 (metadata, "nfo:averageBitrate", 
stream->data.stream_info.bits_per_sample);
+               tracker_resource_set_int64 (metadata, "nfo:duration", stream->data.stream_info.total_samples 
/ stream->data.stream_info.sample_rate);
        }
 
        g_free (fd.artist);
diff --git a/src/tracker-extract/tracker-extract-gif.c b/src/tracker-extract/tracker-extract-gif.c
index 27ee316..8e96199 100644
--- a/src/tracker-extract/tracker-extract-gif.c
+++ b/src/tracker-extract/tracker-extract-gif.c
@@ -102,14 +102,11 @@ static inline void print_gif_error()
 #define DGifCloseFile(a, b) DGifCloseFile(a)
 #endif
 
-static void
-read_metadata (TrackerSparqlBuilder *preupdate,
-               TrackerSparqlBuilder *metadata,
-               GifFileType          *gifFile,
-               const gchar          *uri,
-               const gchar          *graph,
-               const gchar          *urn)
+static TrackerResource *
+read_metadata (GifFileType          *gifFile,
+               const gchar          *uri)
 {
+       TrackerResource *metadata;
        GifRecordType RecordType;
        int frameheight;
        int framewidth;
@@ -133,7 +130,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
 #else  /* GIFLIB_MAJOR < 5 */
                        gif_error ("Could not read next GIF record type", gifFile->Error);
 #endif /* GIFLIB_MAJOR < 5 */
-                       return;
+                       return NULL;
                }
 
                switch (RecordType) {
@@ -144,7 +141,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
 #else  /* GIFLIB_MAJOR < 5 */
                                gif_error ("Could not get GIF record information", gifFile->Error);
 #endif /* GIFLIB_MAJOR < 5 */
-                               return;
+                               return NULL;
                        }
 
                        framewidth  = gifFile->Image.Width;
@@ -159,7 +156,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
 #else  /* GIFLIB_MAJOR < 5 */
                                        gif_error ("Could not load a block of GIF pixes", gifFile->Error);
 #endif /* GIFLIB_MAJOR < 5 */
-                                       return;
+                                       return NULL;
                                }
                        }
 
@@ -176,7 +173,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
 
                        if ((status = DGifGetExtension (gifFile, &ExtCode, &ExtData)) != GIF_OK) {
                                g_warning ("Problem getting the extension");
-                               return;
+                               return NULL;
                        }
 #if defined(HAVE_EXEMPI)
                        if (ExtData && *ExtData &&
@@ -186,7 +183,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
                                                if (ExtData != NULL) {
                                                        if (ext_block_append (&extBlock, ExtData[0]+1, (char 
*) &(ExtData[0])) != GIF_OK) {
                                                                g_warning ("Problem with extension data");
-                                                               return;
+                                                               return NULL;
                                                        }
                                                }
                                        }
@@ -213,7 +210,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
                                                 ExtData[0]);
                                        if (ext_block_append (&extBlock, ExtData[0], (char *) &(ExtData[1])) 
!= GIF_OK) {
                                                g_warning ("Problem with Comment extension data");
-                                               return;
+                                               return NULL;
                                        }
                                } while (((status = DGifGetExtensionNext(gifFile, &ExtData)) == GIF_OK) &&
                                         ExtData != NULL);
@@ -249,153 +246,86 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        md.date = tracker_coalesce_strip (2, xd->date, xd->time_original);
        md.artist = tracker_coalesce_strip (2, xd->artist, xd->contributor);
 
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:Photo");
+
        if (xd->license) {
-               tracker_sparql_builder_predicate (metadata, "nie:license");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->license);
+               tracker_resource_set_string (metadata, "nie:license", xd->license);
        }
 
        if (xd->creator) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->creator);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               TrackerResource *creator = tracker_extract_new_contact (xd->creator);
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, xd->creator);
+               tracker_resource_set_relation (metadata, "nco:creator", creator);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (creator);
        }
 
-       tracker_guarantee_date_from_file_mtime (metadata,
-                                               "nie:contentCreated",
-                                               md.date,
-                                               uri);
+       tracker_guarantee_resource_date_from_file_mtime (metadata,
+                                                        "nie:contentCreated",
+                                                        md.date,
+                                                        uri);
 
        if (xd->description) {
-               tracker_sparql_builder_predicate (metadata, "nie:description");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->description);
+               tracker_resource_set_string (metadata, "nie:description", xd->description);
        }
 
        if (xd->copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->copyright);
+               tracker_resource_set_string (metadata, "nie:copyright", xd->copyright);
        }
 
        if (xd->make || xd->model) {
-               gchar *equip_uri;
-
-               equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                             xd->make ? xd->make : "",
-                                                             xd->model ? xd->model : "");
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:Equipment");
+               TrackerResource *equipment = tracker_extract_new_equipment (xd->make, xd->model);
 
-               if (xd->make) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                       tracker_sparql_builder_object_unvalidated (preupdate, xd->make);
-               }
-               if (xd->model) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                       tracker_sparql_builder_object_unvalidated (preupdate, xd->model);
-               }
+               tracker_resource_set_relation (metadata, "nfo:equipment", equipment);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-               tracker_sparql_builder_object_iri (metadata, equip_uri);
-               g_free (equip_uri);
+               g_object_unref (equipment);
        }
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          md.title,
-                                          uri,
-                                          NULL);
+       tracker_guarantee_resource_title_from_file (metadata,
+                                                   "nie:title",
+                                                   md.title,
+                                                   uri,
+                                                   NULL);
 
        if (md.artist) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
+               TrackerResource *artist = tracker_extract_new_contact (xd->creator);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               tracker_resource_add_relation (metadata, "nco:contributor", artist);
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (artist);
        }
 
        if (xd->orientation) {
-               tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->orientation);
+               tracker_resource_set_string (metadata, "nfo:orientation", xd->orientation);
        }
 
        if (xd->exposure_time) {
-               tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->exposure_time);
+               tracker_resource_set_string (metadata, "nmm:exposureTime", xd->exposure_time);
        }
 
        if (xd->iso_speed_ratings) {
-               tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->iso_speed_ratings);
+               tracker_resource_set_string (metadata, "nmm:isoSpeed", xd->iso_speed_ratings);
        }
 
        if (xd->white_balance) {
-               tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->white_balance);
+               tracker_resource_set_string (metadata, "nmm:whiteBalance", xd->white_balance);
        }
 
        if (xd->fnumber) {
-               tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->fnumber);
+               tracker_resource_set_string (metadata, "nmm:fnumber", xd->fnumber);
        }
 
        if (xd->flash) {
-               tracker_sparql_builder_predicate (metadata, "nmm:flash");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->flash);
-       }
+               tracker_resource_set_string (metadata, "nmm:flash", xd->flash); }
 
        if (xd->focal_length) {
-               tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->focal_length);
+               tracker_resource_set_string (metadata, "nmm:focalLength", xd->focal_length);
        }
 
        if (xd->metering_mode) {
-               tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->metering_mode);
+               tracker_resource_set_string (metadata, "nmm:meteringMode", xd->metering_mode);
        }
 
        keywords = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
@@ -409,8 +339,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        }
 
        if (xd->rating) {
-               tracker_sparql_builder_predicate (metadata, "nao:numericRating");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
+               tracker_resource_set_string (metadata, "nao:numericRating", xd->rating);
        }
 
        if (xd->subject) {
@@ -418,216 +347,101 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        }
 
         if (xd->regions) {
-                tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
+                tracker_xmp_apply_regions_to_resource (metadata, xd);
         }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *escaped, *subject;
+               TrackerResource *tag;
                const gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               subject = g_strdup_printf ("_:tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject (preupdate, subject);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_append (preupdate,
-                                              "WHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
-
-               /* associate file with tag */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject_iri (preupdate, urn);
-               tracker_sparql_builder_predicate (preupdate, "nao:hasTag");
-               tracker_sparql_builder_object (preupdate, "?tag");
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject (preupdate, "?tag");
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_where_close (preupdate);
-
-               g_free (subject);
-               g_free (escaped);
+               tag = tracker_extract_new_tag (p);
+
+               tracker_resource_set_relation (metadata, "nao:hasTag", tag);
+
+               g_object_unref (tag);
        }
        g_ptr_array_free (keywords, TRUE);
 
        if (xd->publisher) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
+               TrackerResource *publisher = tracker_extract_new_contact (xd->creator);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               tracker_resource_add_relation (metadata, "nco:creator", publisher);
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (publisher);
        }
 
        if (xd->type) {
-               tracker_sparql_builder_predicate (metadata, "dc:type");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->type);
+               tracker_resource_set_string (metadata, "dc:type", xd->type);
        }
 
        if (xd->format) {
-               tracker_sparql_builder_predicate (metadata, "dc:format");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->format);
+               tracker_resource_set_string (metadata, "dc:format", xd->format);
        }
 
        if (xd->identifier) {
-               tracker_sparql_builder_predicate (metadata, "dc:identifier");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
+               tracker_resource_set_string (metadata, "dc:identifier", xd->identifier);
        }
 
        if (xd->source) {
-               tracker_sparql_builder_predicate (metadata, "dc:source");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->source);
+               tracker_resource_set_string (metadata, "dc:source", xd->source);
        }
 
        if (xd->language) {
-               tracker_sparql_builder_predicate (metadata, "dc:language");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->language);
+               tracker_resource_set_string (metadata, "dc:language", xd->language);
        }
 
        if (xd->relation) {
-               tracker_sparql_builder_predicate (metadata, "dc:relation");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
+               tracker_resource_set_string (metadata, "dc:relation", xd->relation);
        }
 
        if (xd->coverage) {
-               tracker_sparql_builder_predicate (metadata, "dc:coverage");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
+               tracker_resource_set_string (metadata, "dc:coverage", xd->coverage);
        }
 
        if (xd->address || xd->state || xd->country || xd->city ||
            xd->gps_altitude || xd->gps_latitude || xd-> gps_longitude) {
 
-               tracker_sparql_builder_predicate (metadata, "slo:location");
+               TrackerResource *location = tracker_extract_new_location (xd->address,
+                       xd->state, xd->city, xd->country, xd->gps_altitude,
+                       xd->gps_latitude, xd->gps_longitude);
 
-               tracker_sparql_builder_object_blank_open (metadata); /* GeoLocation */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
+               tracker_resource_set_relation (metadata, "slo:location", location);
 
-               if (xd->address || xd->state || xd->country || xd->city)  {
-                       gchar *addruri;
-                       addruri = tracker_sparql_get_uuid_urn ();
-
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, addruri);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, addruri);
-
-                       g_free (addruri);
-
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
-
-                       if (xd->address) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->address);
-                       }
-
-                       if (xd->state) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:region");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->state);
-                       }
-
-                       if (xd->city) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->city);
-                       }
-
-                       if (xd->country) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:country");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->country);
-                       }
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-
-               if (xd->gps_altitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_altitude);
-               }
-
-               if (xd->gps_latitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_latitude);
-               }
-
-               if (xd->gps_longitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_longitude);
-               }
-
-               tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+               g_object_unref (location);
        }
 
        if (xd->gps_direction) {
-               tracker_sparql_builder_predicate (metadata, "nfo:heading");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->gps_direction);
+               tracker_resource_set_string (metadata, "nfo:heading", xd->gps_direction);
        }
 
        if (gd.width) {
-               tracker_sparql_builder_predicate (metadata, "nfo:width");
-               tracker_sparql_builder_object_unvalidated (metadata, gd.width);
+               tracker_resource_set_string (metadata, "nfo:width", gd.width);
                g_free (gd.width);
        }
 
        if (gd.height) {
-               tracker_sparql_builder_predicate (metadata, "nfo:height");
-               tracker_sparql_builder_object_unvalidated (metadata, gd.height);
+               tracker_resource_set_string (metadata, "nfo:height", gd.height);
                g_free (gd.height);
        }
 
        if (gd.comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, gd.comment);
+               tracker_resource_set_string (metadata, "nie:comment", gd.comment);
                g_free (gd.comment);
        }
 
        tracker_xmp_free (xd);
+
+       return metadata;
 }
 
 
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *preupdate, *metadata;
+       TrackerResource *metadata;
        goffset size;
        GifFileType *gifFile = NULL;
-       const gchar *graph, *urn;
        gchar *filename, *uri;
        GFile *file;
        int fd;
@@ -635,11 +449,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        int err;
 #endif
 
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-       urn = tracker_extract_info_get_urn (info);
-
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
        size = tracker_file_get_size (filename);
@@ -673,13 +482,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        g_free (filename);
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_object (metadata, "nmm:Photo");
-
        uri = g_file_get_uri (file);
 
-       read_metadata (preupdate, metadata, gifFile, uri, graph, urn);
+       metadata = read_metadata (gifFile, uri);
 
        g_free (uri);
 
@@ -691,5 +496,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 #endif /* GIFLIB_MAJOR < 5 */
        }
 
+       if (metadata) {
+               tracker_extract_info_set_resource (info, metadata);
+               g_object_unref (metadata);
+       }
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-gstreamer.c b/src/tracker-extract/tracker-extract-gstreamer.c
index 0fcec89..042a08b 100644
--- a/src/tracker-extract/tracker-extract-gstreamer.c
+++ b/src/tracker-extract/tracker-extract-gstreamer.c
@@ -2,6 +2,7 @@
  * Copyright (C) 2006, Laurent Aguerreche <laurent aguerreche free fr>
  * Copyright (C) 2007, Jamie McCracken <jamiemcc gnome org>
  * Copyright (C) 2008, Nokia <ivan frade nokia com>
+ * Copyright (C) 2016, Sam Thursfield <sam afuera me uk>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -152,95 +153,44 @@ typedef struct {
 
 static void common_extract_stream_metadata (MetadataExtractor    *extractor,
                                             const gchar          *uri,
-                                            TrackerSparqlBuilder *metadata);
+                                            TrackerResource      *resource);
 
-static void
-add_artist (MetadataExtractor     *extractor,
-            TrackerSparqlBuilder  *preupdate,
-            const gchar           *graph,
-            const gchar           *artist_name,
-            gchar                **p_artist_uri)
+static TrackerResource *
+intern_artist (MetadataExtractor     *extractor,
+               const gchar           *artist_name)
 {
-       g_return_if_fail (artist_name != NULL);
+       GSList *node;
+       TrackerResource *artist;
+       gchar *artist_uri;
 
-       *p_artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", artist_name);
+       g_return_val_if_fail (artist_name != NULL, NULL);
 
-       /* Check if already added to the preupdate, to avoid sending 9 identical INSERTs */
-       if (g_slist_find_custom (extractor->artist_list, artist_name, (GCompareFunc) strcmp))
-               return;
+       artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", artist_name);
 
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
+       node = g_slist_find_custom (extractor->artist_list, artist_uri,
+                                   (GCompareFunc) tracker_resource_identifier_compare_func);
+       if (node) {
+               return node->data;
        }
 
-       tracker_sparql_builder_subject_iri (preupdate, *p_artist_uri);
-       tracker_sparql_builder_predicate (preupdate, "a");
-       tracker_sparql_builder_object (preupdate, "nmm:Artist");
-       tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-       tracker_sparql_builder_object_unvalidated (preupdate, artist_name);
+       artist = tracker_extract_new_artist (artist_name);
 
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
+       extractor->artist_list = g_slist_prepend (extractor->artist_list, artist);
 
-       extractor->artist_list = g_slist_prepend (extractor->artist_list, g_strdup (artist_name));
+       return artist;
 }
 
 static void
-add_string_gst_tag (TrackerSparqlBuilder *metadata,
-                    const gchar          *key,
-                    GstTagList           *tag_list,
-                    const gchar          *tag)
+set_property_from_gst_tag (TrackerResource *resource,
+                           const gchar     *property_uri,
+                           GstTagList      *tag_list,
+                           const gchar     *tag)
 {
-       gchar *s;
-       gboolean ret;
+       GValue value = G_VALUE_INIT;
 
-       s = NULL;
-       ret = gst_tag_list_get_string (tag_list, tag, &s);
-
-       if (s) {
-               if (ret && s[0] != '\0') {
-                       tracker_sparql_builder_predicate (metadata, key);
-                       tracker_sparql_builder_object_unvalidated (metadata, s);
-               }
-
-               g_free (s);
-       }
-}
-
-static void
-add_uint_gst_tag (TrackerSparqlBuilder  *metadata,
-                  const gchar           *key,
-                  GstTagList            *tag_list,
-                  const gchar           *tag)
-{
-       gboolean ret;
-       guint n;
-
-       ret = gst_tag_list_get_uint (tag_list, tag, &n);
-
-       if (ret) {
-               tracker_sparql_builder_predicate (metadata, key);
-               tracker_sparql_builder_object_int64 (metadata, n);
-       }
-}
-
-static void
-add_double_gst_tag (TrackerSparqlBuilder  *metadata,
-                    const gchar           *key,
-                    GstTagList            *tag_list,
-                    const gchar           *tag)
-{
-       gboolean ret;
-       gdouble n;
-
-       ret = gst_tag_list_get_double (tag_list, tag, &n);
-
-       if (ret) {
-               tracker_sparql_builder_predicate (metadata, key);
-               tracker_sparql_builder_object_int64 (metadata, (gint64) n);
+       if (gst_tag_list_copy_value (&value, tag_list, tag)) {
+               tracker_resource_set_gvalue (resource, property_uri, &value);
+               g_value_unset (&value);
        }
 }
 
@@ -312,12 +262,12 @@ get_gst_date_time_to_buf (GstDateTime *date_time,
 }
 
 static void
-add_date_time_gst_tag_with_mtime_fallback (TrackerSparqlBuilder  *metadata,
-                                           const gchar           *uri,
-                                           const gchar           *key,
-                                           GstTagList            *tag_list,
-                                           const gchar           *tag_date_time,
-                                           const gchar           *tag_date)
+add_date_time_gst_tag_with_mtime_fallback (TrackerResource *resource,
+                                           const gchar     *uri,
+                                           const gchar     *key,
+                                           GstTagList      *tag_list,
+                                           const gchar     *tag_date_time,
+                                           const gchar     *tag_date)
 {
        GstDateTime *date_time;
        GDate *date;
@@ -356,12 +306,12 @@ add_date_time_gst_tag_with_mtime_fallback (TrackerSparqlBuilder  *metadata,
                g_date_free (date);
        }
 
-       tracker_guarantee_date_from_file_mtime (metadata, key, buf, uri);
+       tracker_guarantee_resource_date_from_file_mtime (resource, key, buf, uri);
 }
 
 static void
-add_keywords_gst_tag (TrackerSparqlBuilder *metadata,
-                      GstTagList           *tag_list)
+set_keywords_from_gst_tag (TrackerResource *resource,
+                           GstTagList      *tag_list)
 {
        gboolean ret;
        gchar *str;
@@ -375,8 +325,7 @@ add_keywords_gst_tag (TrackerSparqlBuilder *metadata,
                keywords = g_strsplit_set (str, " ,", -1);
 
                while (keywords[i]) {
-                       tracker_sparql_builder_predicate (metadata, "nie:keyword");
-                       tracker_sparql_builder_object_unvalidated (metadata, g_strstrip (keywords[i]));
+                       tracker_resource_add_string (resource, "nie:keyword", g_strstrip (keywords[i]));
                        i++;
                }
 
@@ -385,49 +334,6 @@ add_keywords_gst_tag (TrackerSparqlBuilder *metadata,
        }
 }
 
-static void
-replace_double_gst_tag (TrackerSparqlBuilder  *preupdate,
-                        const gchar           *uri,
-                        const gchar           *key,
-                        GstTagList            *tag_list,
-                        const gchar           *tag,
-                        const gchar           *graph)
-{
-       gdouble  value;
-       gboolean has_it;
-
-       has_it = gst_tag_list_get_double (tag_list, tag, &value);
-
-       if (! has_it)
-               return;
-
-       tracker_sparql_builder_delete_open (preupdate, NULL);
-       tracker_sparql_builder_subject_iri (preupdate, uri);
-       tracker_sparql_builder_predicate (preupdate, key);
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_delete_close (preupdate);
-
-       tracker_sparql_builder_where_open (preupdate);
-       tracker_sparql_builder_subject_iri (preupdate, uri);
-       tracker_sparql_builder_predicate (preupdate, key);
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_where_close (preupdate);
-
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
-       }
-
-       tracker_sparql_builder_subject_iri (preupdate, uri);
-       tracker_sparql_builder_predicate (preupdate, key);
-       tracker_sparql_builder_object_double (preupdate, value);
-
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
-}
-
 static gchar *
 get_embedded_cue_sheet_data (GstTagList *tag_list)
 {
@@ -572,95 +478,67 @@ get_embedded_media_art (MetadataExtractor *extractor)
 
 #endif
 
-static void
-extractor_apply_geolocation_metadata (MetadataExtractor     *extractor,
-                                      GstTagList            *tag_list,
-                                      TrackerSparqlBuilder  *preupdate,
-                                      TrackerSparqlBuilder  *metadata,
-                                      const gchar           *graph)
+static TrackerResource *
+extractor_get_geolocation (MetadataExtractor     *extractor,
+                           GstTagList            *tag_list)
 {
-       gchar *country = NULL, *city = NULL, *sublocation = NULL;
+       TrackerResource *location = NULL;
        gdouble lat, lon, alt;
        gboolean has_coords;
 
        g_debug ("Retrieving geolocation metadata...");
 
-       country = city = sublocation = NULL;
        has_coords = (gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LATITUDE, &lat) &&
                      gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LONGITUDE, &lon) &&
                      gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_ELEVATION, &alt));
 
-       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_CITY, &city);
-       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_COUNTRY, &country);
-       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_SUBLOCATION, &sublocation);
-
-       if (city || country || sublocation || has_coords) {
-               gchar *address_uri = NULL;
-
-               /* Create postal address */
-               if (city || country || sublocation) {
-                       address_uri = tracker_sparql_get_uuid_urn ();
+       if (has_coords) {
+               location = tracker_resource_new (NULL);
+               tracker_resource_set_uri (location, "rdf:type", "slo:GeoLocation");
 
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
+               tracker_resource_set_double (location, "slo:latitude", lat);
+               tracker_resource_set_double (location, "slo:longitude", lon);
+               tracker_resource_set_double (location, "slo:altitude", alt);
+       }
 
-                       tracker_sparql_builder_subject_iri (preupdate, address_uri);
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
+       return location;
+}
 
-                       if (sublocation) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:region");
-                               tracker_sparql_builder_object_unvalidated (preupdate, sublocation);
-                       }
+static TrackerResource *
+extractor_get_address (MetadataExtractor     *extractor,
+                       GstTagList            *tag_list)
+{
+       TrackerResource *address = NULL;
+       gchar *country = NULL, *city = NULL, *sublocation = NULL;
 
-                       if (city) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                               tracker_sparql_builder_object_unvalidated (preupdate, city);
-                       }
+       g_debug ("Retrieving address metadata...");
 
-                       if (country) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:country");
-                               tracker_sparql_builder_object_unvalidated (preupdate, country);
-                       }
+       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_CITY, &city);
+       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_COUNTRY, &country);
+       gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_SUBLOCATION, &sublocation);
 
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
+       if (city || country || sublocation) {
+               gchar *address_uri = NULL;
 
-               /* Create geolocation */
-               tracker_sparql_builder_predicate (metadata, "slo:location");
+               address_uri = tracker_sparql_get_uuid_urn ();
+               address = tracker_resource_new (address_uri);
 
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
+               tracker_resource_set_string (address, "rdf:type", "nco:PostalAddress");
 
-               if (address_uri) {
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, address_uri);
+               if (sublocation) {
+                       tracker_resource_set_string (address, "nco:region", sublocation);
                }
 
-               if (has_coords) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_double (metadata, lat);
-
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_double (metadata, lon);
-
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_double (metadata, alt);
+               if (city) {
+                       tracker_resource_set_string (address, "nco:locality", city);
                }
 
-               tracker_sparql_builder_object_blank_close (metadata);
-               g_free (address_uri);
+               if (country) {
+                       tracker_resource_set_string (address, "nco:country", country);
+               }
        }
 
-       g_free (city);
-       g_free (country);
-       g_free (sublocation);
+       return address;
 }
 
 static void
@@ -682,59 +560,59 @@ static void
 extractor_apply_general_metadata (MetadataExtractor     *extractor,
                                   GstTagList            *tag_list,
                                   const gchar           *file_url,
-                                  TrackerSparqlBuilder  *preupdate,
-                                  TrackerSparqlBuilder  *metadata,
-                                  const gchar           *graph,
-                                  gchar                **p_performer_uri,
-                                  gchar                **p_composer_uri)
+                                  TrackerResource       *resource,
+                                  TrackerResource      **p_performer,
+                                  TrackerResource      **p_composer)
 {
-       const gchar *performer = NULL;
+       const gchar *performer_name = NULL;
        gchar *performer_temp = NULL;
        gchar *artist_temp = NULL;
-       gchar *composer = NULL;
+       gchar *composer_name = NULL;
        gchar *genre = NULL;
        gchar *title = NULL;
        gchar *title_guaranteed = NULL;
 
+       *p_composer = NULL;
+       *p_performer = NULL;
+
        gst_tag_list_get_string (tag_list, GST_TAG_PERFORMER, &performer_temp);
        gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &artist_temp);
-       gst_tag_list_get_string (tag_list, GST_TAG_COMPOSER, &composer);
+       gst_tag_list_get_string (tag_list, GST_TAG_COMPOSER, &composer_name);
 
-       performer = tracker_coalesce_strip (2, performer_temp, artist_temp);
+       performer_name = tracker_coalesce_strip (2, performer_temp, artist_temp);
 
-       if (performer != NULL) {
-               add_artist (extractor, preupdate, graph, performer, p_performer_uri);
+       if (performer_name != NULL) {
+               *p_performer = intern_artist (extractor, performer_name);
        }
 
-       if (composer != NULL) {
-               add_artist (extractor, preupdate, graph, composer, p_composer_uri);
+       if (composer_name != NULL) {
+               *p_composer = intern_artist (extractor, composer_name);
        }
 
        gst_tag_list_get_string (tag_list, GST_TAG_GENRE, &genre);
        gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &title);
 
        if (genre && g_strcmp0 (genre, "Unknown") != 0) {
-               tracker_sparql_builder_predicate (metadata, "nfo:genre");
-               tracker_sparql_builder_object_unvalidated (metadata, genre);
+               tracker_resource_add_string (resource, "nfo:genre", genre);
        }
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          title,
-                                          file_url,
-                                          &title_guaranteed);
+       tracker_guarantee_resource_title_from_file (resource,
+                                                  "nie:title",
+                                                   title,
+                                                   file_url,
+                                                   &title_guaranteed);
 
-       add_date_time_gst_tag_with_mtime_fallback (metadata,
+       add_date_time_gst_tag_with_mtime_fallback (resource,
                                                   file_url,
                                                   "nie:contentCreated",
                                                   tag_list,
                                                   GST_TAG_DATE_TIME,
                                                   GST_TAG_DATE);
 
-       add_string_gst_tag (metadata, "nie:copyright", tag_list, GST_TAG_COPYRIGHT);
-       add_string_gst_tag (metadata, "nie:license", tag_list, GST_TAG_LICENSE);
-       add_string_gst_tag (metadata, "dc:coverage", tag_list, GST_TAG_LOCATION);
-       add_string_gst_tag (metadata, "nie:comment", tag_list, GST_TAG_COMMENT);
+       set_property_from_gst_tag (resource, "nie:copyright", tag_list, GST_TAG_COPYRIGHT);
+       set_property_from_gst_tag (resource, "nie:license", tag_list, GST_TAG_LICENSE);
+       set_property_from_gst_tag (resource, "dc:coverage", tag_list, GST_TAG_LOCATION);
+       set_property_from_gst_tag (resource, "nie:comment", tag_list, GST_TAG_COMMENT);
 
 #ifdef HAVE_LIBMEDIAART
        if (extractor->media_art_type == MEDIA_ART_VIDEO) {
@@ -748,312 +626,187 @@ extractor_apply_general_metadata (MetadataExtractor     *extractor,
 
        g_free (performer_temp);
        g_free (artist_temp);
-       g_free (composer);
+       g_free (composer_name);
        g_free (genre);
        g_free (title);
 }
 
-static void
-extractor_apply_album_metadata (MetadataExtractor     *extractor,
-                                GstTagList            *tag_list,
-                                TrackerSparqlBuilder  *preupdate,
-                                const gchar           *graph,
-                                gchar                **p_album_artist_uri,
-                                gchar                **p_album_uri,
-                                gchar                **p_album_disc_uri)
+static TrackerResource *
+extractor_maybe_get_album_disc (MetadataExtractor *extractor,
+                                GstTagList        *tag_list)
 {
-       gchar *album_artist;
+       TrackerResource *album = NULL, *album_artist = NULL, *album_disc = NULL;
+       gchar *album_uri, *album_disc_uri;
+       gchar *album_artist_name;
        gchar *album_title = NULL;
        gchar *album_artist_temp = NULL;
        gchar *track_artist_temp = NULL;
        gboolean has_it;
-       guint count;
+       guint volume_number;
 
        gst_tag_list_get_string (tag_list, GST_TAG_ALBUM, &album_title);
 
        if (!album_title)
-               return;
+               return NULL;
 
        gst_tag_list_get_string (tag_list, GST_TAG_ALBUM_ARTIST, &album_artist_temp);
        gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &track_artist_temp);
 
-       album_artist = g_strdup (tracker_coalesce_strip (2, album_artist_temp, track_artist_temp));
+       album_artist_name = g_strdup (tracker_coalesce_strip (2, album_artist_temp, track_artist_temp));
 
-        if (album_artist != NULL) {
-                add_artist (extractor, preupdate, graph, album_artist, p_album_artist_uri);
-                *p_album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s:%s", album_title, 
album_artist);
+        if (album_artist_name != NULL) {
+                album_artist = intern_artist (extractor, album_artist_name);
+                album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s:%s", album_title, 
album_artist_name);
         } else {
-                *p_album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", album_title);
+                album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", album_title);
         }
 
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
-       }
+       album = tracker_resource_new (album_uri);
+       tracker_resource_set_uri (album, "rdf:type", "nmm:MusicAlbum");
 
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_uri);
-       tracker_sparql_builder_predicate (preupdate, "a");
-       tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum");
-       /* FIXME: nmm:albumTitle is now deprecated
-        * tracker_sparql_builder_predicate (preupdate, "nie:title");
-        */
-       tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle");
-       tracker_sparql_builder_object_unvalidated (preupdate, album_title);
+       /* FIXME: nmm:albumTitle is now deprecated, should use nie:title ??  */
+       tracker_resource_set_string (album, "nmm:albumTitle", album_title);
 
-       if (*p_album_artist_uri) {
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumArtist");
-               tracker_sparql_builder_object_iri (preupdate, *p_album_artist_uri);
+       if (album_artist) {
+               tracker_resource_set_relation (album, "nmm:albumArtist", album_artist);
        }
 
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
-
-       has_it = gst_tag_list_get_uint (tag_list, GST_TAG_TRACK_COUNT, &count);
-
-       if (has_it) {
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, *p_album_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, *p_album_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, *p_album_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-               tracker_sparql_builder_object_int64 (preupdate, count);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-       }
+       set_property_from_gst_tag (album, "nmm:albumTrackCount", tag_list, GST_TAG_TRACK_COUNT);
 
-       has_it = gst_tag_list_get_uint (tag_list, GST_TAG_ALBUM_VOLUME_NUMBER, &count);
+       has_it = gst_tag_list_get_uint (tag_list, GST_TAG_ALBUM_VOLUME_NUMBER, &volume_number);
 
         if (album_artist) {
-                *p_album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:%s:Disc%d",
-                                                                      album_title, album_artist,
-                                                                      has_it ? count : 1);
+                album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:%s:Disc%d",
+                                                                   album_title, album_artist,
+                                                                   has_it ? volume_number : 1);
         } else {
-                *p_album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
-                                                                      album_title,
-                                                                      has_it ? count : 1);
+                album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
+                                                                   album_title,
+                                                                   has_it ? volume_number : 1);
         }
 
+       album_disc = tracker_resource_new (album_disc_uri);
+       tracker_resource_set_uri (album_disc, "rdf:type", "nmm:MusicAlbumDisc");
+       tracker_resource_set_int64 (album_disc, "nmm:setNumber", has_it ? volume_number : 1);
+       tracker_resource_set_relation (album_disc, "nmm:albumDiscAlbum", album);
 
-       tracker_sparql_builder_delete_open (preupdate, NULL);
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri);
-       tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_delete_close (preupdate);
-       tracker_sparql_builder_where_open (preupdate);
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri);
-       tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_where_close (preupdate);
-
-       tracker_sparql_builder_delete_open (preupdate, NULL);
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri);
-       tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_delete_close (preupdate);
-       tracker_sparql_builder_where_open (preupdate);
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri);
-       tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-       tracker_sparql_builder_object_variable (preupdate, "unknown");
-       tracker_sparql_builder_where_close (preupdate);
-
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
-       }
-
-       tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri);
-       tracker_sparql_builder_predicate (preupdate, "a");
-       tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc");
-       tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-       tracker_sparql_builder_object_int64 (preupdate, has_it ? count : 1);
-       tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-       tracker_sparql_builder_object_iri (preupdate, *p_album_uri);
-
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
-
-       replace_double_gst_tag (preupdate, *p_album_uri, "nmm:albumGain", extractor->tagcache, 
GST_TAG_ALBUM_GAIN, graph);
-       replace_double_gst_tag (preupdate, *p_album_uri, "nmm:albumPeakGain", extractor->tagcache, 
GST_TAG_ALBUM_PEAK, graph);
+       set_property_from_gst_tag (album, "nmm:albumGain", extractor->tagcache, GST_TAG_ALBUM_GAIN);
+       set_property_from_gst_tag (album, "nmm:albumPeakGain", extractor->tagcache, GST_TAG_ALBUM_PEAK);
 
 #ifdef HAVE_LIBMEDIAART
-       extractor->media_art_artist = album_artist;
+       extractor->media_art_artist = album_artist_name;
        extractor->media_art_title = album_title;
 #endif
 
        g_free (album_artist_temp);
        g_free (track_artist_temp);
+
+       return album_disc;
 }
 
-static void
-extractor_apply_device_metadata (MetadataExtractor    *extractor,
-                                 GstTagList           *tag_list,
-                                 TrackerSparqlBuilder *preupdate,
-                                 TrackerSparqlBuilder *metadata,
-                                 const gchar          *graph)
+static TrackerResource *
+extractor_get_equipment (MetadataExtractor    *extractor,
+                         GstTagList           *tag_list)
 {
-       gchar *equip_uri;
+       TrackerResource *equipment;
        gchar *model = NULL, *manuf = NULL;
 
        gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MODEL, &model);
        gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MANUFACTURER, &manuf);
 
        if (model == NULL && manuf == NULL)
-               return;
-
-       equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                     manuf ? manuf : "",
-                                                     model ? model : "");
-
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
-       }
-
-       tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-       tracker_sparql_builder_predicate (preupdate, "a");
-       tracker_sparql_builder_object (preupdate, "nfo:Equipment");
-
-       if (manuf) {
-               tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-               tracker_sparql_builder_object_unvalidated (preupdate, manuf);
-       }
-       if (model) {
-               tracker_sparql_builder_predicate (preupdate, "nfo:model");
-               tracker_sparql_builder_object_unvalidated (preupdate, model);
-       }
-
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
+               return NULL;
 
-       tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-       tracker_sparql_builder_object_iri (metadata, equip_uri);
+       equipment = tracker_extract_new_equipment (manuf, model);
 
-       g_free (equip_uri);
        g_free (model);
        g_free (manuf);
+
+       return equipment;
 }
 
 static void
 extractor_apply_audio_metadata (MetadataExtractor     *extractor,
                                 GstTagList            *tag_list,
-                                TrackerSparqlBuilder  *metadata,
-                                const gchar           *performer_uri,
-                                const gchar           *composer_uri,
-                                const gchar           *album_uri,
-                                const gchar           *album_disc_uri)
+                                TrackerResource       *audio,
+                                TrackerResource       *performer,
+                                TrackerResource       *composer,
+                                TrackerResource       *album_disc)
 {
-       add_uint_gst_tag (metadata, "nmm:trackNumber", tag_list, GST_TAG_TRACK_NUMBER);
-       add_string_gst_tag (metadata, "nfo:codec", tag_list, GST_TAG_AUDIO_CODEC);
-       add_double_gst_tag (metadata, "nfo:gain", tag_list, GST_TAG_TRACK_GAIN);
-       add_double_gst_tag (metadata, "nfo:peakGain", tag_list, GST_TAG_TRACK_PEAK);
-
-       if (performer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:performer");
-               tracker_sparql_builder_object_iri (metadata, performer_uri);
-       }
+       set_property_from_gst_tag (audio, "nmm:trackNumber", tag_list, GST_TAG_TRACK_NUMBER);
+       set_property_from_gst_tag (audio, "nfo:codec", tag_list, GST_TAG_AUDIO_CODEC);
+       set_property_from_gst_tag (audio, "nfo:gain", tag_list, GST_TAG_TRACK_GAIN);
+       set_property_from_gst_tag (audio, "nfo:peakGain", tag_list, GST_TAG_TRACK_PEAK);
 
-       if (composer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:composer");
-               tracker_sparql_builder_object_iri (metadata, composer_uri);
+       if (performer) {
+               tracker_resource_set_relation (audio, "nmm:performer", performer);
        }
 
-       if (album_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbum");
-               tracker_sparql_builder_object_iri (metadata, album_uri);
+       if (composer) {
+               tracker_resource_set_relation (audio, "nmm:composer", composer);
        }
 
-       if (album_disc_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc");
-               tracker_sparql_builder_object_iri (metadata, album_disc_uri);
+       if (album_disc) {
+               TrackerResource *album;
+               album = tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum");
+
+               tracker_resource_set_relation (audio, "nmm:musicAlbumDisc", album_disc);
+               tracker_resource_set_relation (audio, "nmm:musicAlbum", album);
        }
 }
 
 static void
-extractor_apply_video_metadata (MetadataExtractor    *extractor,
-                                GstTagList           *tag_list,
-                                TrackerSparqlBuilder *metadata,
-                                const gchar          *performer_uri,
-                                const gchar          *composer_uri)
+extractor_apply_video_metadata (MetadataExtractor *extractor,
+                                GstTagList        *tag_list,
+                                TrackerResource   *video,
+                                TrackerResource   *performer,
+                                TrackerResource   *composer)
 {
-       add_string_gst_tag (metadata, "dc:source", tag_list, GST_TAG_CLASSIFICATION);
+       set_property_from_gst_tag (video, "dc:source", tag_list, GST_TAG_CLASSIFICATION);
 
-       if (performer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:leadActor");
-               tracker_sparql_builder_object_iri (metadata, performer_uri);
+       if (performer) {
+               tracker_resource_set_relation (video, "nmm:leadActor", performer);
        }
 
-       if (composer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:director");
-               tracker_sparql_builder_object_iri (metadata, composer_uri);
+       if (composer) {
+               tracker_resource_set_relation (video, "nmm:director", composer);
        }
 
-       add_keywords_gst_tag (metadata, tag_list);
+       set_keywords_from_gst_tag (video, tag_list);
 }
 
-static void
-extract_track_metadata (MetadataExtractor    *extractor,
-                        TrackerTocEntry      *toc_entry,
-                        const gchar          *file_url,
-                        TrackerSparqlBuilder *preupdate,
-                        TrackerSparqlBuilder *postupdate,
-                        const gchar          *graph,
-                        const gchar          *album_uri,
-                        const gchar          *album_disc_uri)
+static TrackerResource *
+extract_track (MetadataExtractor    *extractor,
+               TrackerTocEntry      *toc_entry,
+               const gchar          *file_url,
+               TrackerResource      *album_disc)
 {
-       gchar *track_performer_uri = NULL;
-       gchar *track_composer_uri = NULL;
+       TrackerResource *track;
+       TrackerResource *track_performer = NULL, *track_composer = NULL;
        gchar *track_uri;
 
        track_uri = tracker_sparql_get_uuid_urn ();
+       track = tracker_resource_new (track_uri);
 
-       tracker_sparql_builder_subject_iri (postupdate, track_uri);
-
-       tracker_sparql_builder_predicate (postupdate, "a");
-       tracker_sparql_builder_object (postupdate, "nmm:MusicPiece");
-       tracker_sparql_builder_object (postupdate, "nfo:Audio");
+       tracker_resource_add_uri (track, "rdf:type", "nmm:MusicPiece");
+       tracker_resource_add_uri (track, "rdf:type", "nfo:Audio");
 
        extractor_apply_general_metadata (extractor,
                                          toc_entry->tag_list,
                                          file_url,
-                                         preupdate,
-                                         postupdate,
-                                         graph,
-                                         &track_performer_uri,
-                                         &track_composer_uri);
+                                         track,
+                                         &track_performer,
+                                         &track_composer);
 
        extractor_apply_audio_metadata (extractor,
                                        toc_entry->tag_list,
-                                       postupdate,
-                                       track_performer_uri,
-                                       track_composer_uri,
-                                       album_uri,
-                                       album_disc_uri);
+                                       track,
+                                       track_performer,
+                                       track_composer,
+                                       album_disc);
 
        if (toc_entry->duration > 0) {
-               tracker_sparql_builder_predicate (postupdate, "nfo:duration");
-               tracker_sparql_builder_object_int64 (postupdate, (gint64)toc_entry->duration);
+               tracker_resource_set_int64 (track, "nfo:duration", (gint64)toc_entry->duration);
        } else if (extractor->toc->entry_list &&
                   toc_entry == g_list_last (extractor->toc->entry_list)->data) {
                /* The last element may not have a duration, because it depends
@@ -1061,58 +814,14 @@ extract_track_metadata (MetadataExtractor    *extractor,
                 * cue sheet. In this case figure the data out from the total
                 * duration.
                 */
-               tracker_sparql_builder_predicate (postupdate, "nfo:duration");
-               tracker_sparql_builder_object_int64 (postupdate,
-                                                    (gint64) extractor->duration - toc_entry->start);
+               tracker_resource_set_int64 (track, "nfo:duration", (gint64)extractor->duration - 
toc_entry->start);
        }
 
-       tracker_sparql_builder_predicate (postupdate, "nfo:audioOffset");
-       tracker_sparql_builder_object_double (postupdate, toc_entry->start);
-
-       /* Link the track to its container file. Since the file might not have been
-        * inserted yet, we use a WHERE clause based on its nie:url to refer to it.
-        */
-       tracker_sparql_builder_predicate (postupdate, "nie:isStoredAs");
-       tracker_sparql_builder_object_variable (postupdate, "file");
-
-       g_free (track_performer_uri);
-       g_free (track_composer_uri);
+       tracker_resource_set_double (track, "nfo:audioOffset", toc_entry->start);
 
        g_free (track_uri);
-}
-
-static void
-delete_existing_tracks (TrackerSparqlBuilder *postupdate,
-                        const gchar          *graph,
-                        const gchar          *file_url)
-{
-       gchar *sparql;
-
-       /* Delete existing tracks */
-
-       tracker_sparql_builder_delete_open (postupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (postupdate, graph);
-       }
-
-       tracker_sparql_builder_subject_variable (postupdate, "track");
-       tracker_sparql_builder_predicate (postupdate, "a");
-       tracker_sparql_builder_object (postupdate, "nmm:MusicPiece");
 
-       if (graph) {
-               tracker_sparql_builder_graph_close (postupdate);
-       }
-       tracker_sparql_builder_delete_close (postupdate);
-
-       sparql = g_strdup_printf ("WHERE { "
-                                 "  ?track a nmm:MusicPiece . "
-                                 "  ?file a nfo:FileDataObject ; "
-                                 "        nie:url \"%s\" . "
-                                 "  ?track nie:isStoredAs ?file "
-                                 "} \n",
-                                 file_url);
-       tracker_sparql_builder_append (postupdate, sparql);
-       g_free (sparql);
+       return track;
 }
 
 #define CHUNK_N_BYTES (2 << 15)
@@ -1166,18 +875,15 @@ end:
        return 0;
 }
 
-static void
+static TrackerResource *
 extract_metadata (MetadataExtractor      *extractor,
-                  const gchar            *file_url,
-                  TrackerSparqlBuilder   *preupdate,
-                  TrackerSparqlBuilder   *postupdate,
-                  TrackerSparqlBuilder   *metadata,
-                  const gchar            *graph)
+                  const gchar            *file_url)
 {
-       g_return_if_fail (extractor != NULL);
-       g_return_if_fail (preupdate != NULL);
-       g_return_if_fail (postupdate != NULL);
-       g_return_if_fail (metadata != NULL);
+       TrackerResource *resource;
+
+       g_return_val_if_fail (extractor != NULL, NULL);
+
+       resource = tracker_resource_new (NULL);
 
 #ifdef HAVE_LIBMEDIAART
        extractor->media_art_type = MEDIA_ART_NONE;
@@ -1225,130 +931,102 @@ extract_metadata (MetadataExtractor      *extractor,
        if (extractor->mime == EXTRACT_MIME_GUESS) {
                g_warning ("Cannot guess real stream type if no tags were read! "
                           "Defaulting to Video.");
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nmm:Video");
+               tracker_resource_add_uri (resource, "rdf:type", "nmm:Video");
        } else {
-               tracker_sparql_builder_predicate (metadata, "a");
-
                if (extractor->mime == EXTRACT_MIME_AUDIO) {
                        /* Audio: don't make an nmm:MusicPiece for the file resource if it's
                         * actually a container for an entire album - we will make a
                         * nmm:MusicPiece for each of the tracks inside instead.
                         */
-                       tracker_sparql_builder_object (metadata, "nfo:Audio");
+                       tracker_resource_add_uri (resource, "rdf:type", "nfo:Audio");
 
                        if (extractor->toc == NULL || extractor->toc->entry_list == NULL)
-                               tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
+                               tracker_resource_add_uri (resource, "rdf:type", "nmm:MusicPiece");
 
 #ifdef HAVE_LIBMEDIAART
                        extractor->media_art_type = MEDIA_ART_ALBUM;
 #endif
                } else if (extractor->mime == EXTRACT_MIME_VIDEO) {
-                       tracker_sparql_builder_object (metadata, "nmm:Video");
+                       tracker_resource_add_uri (resource, "rdf:type", "nmm:Video");
 
 #ifdef HAVE_LIBMEDIAART
                        extractor->media_art_type = MEDIA_ART_VIDEO;
 #endif
                } else {
-                       tracker_sparql_builder_object (metadata, "nfo:Image");
-                       tracker_sparql_builder_object (metadata, "nmm:Photo");
+                       tracker_resource_add_uri (resource, "rdf:type", "nfo:Image");
+                       tracker_resource_add_uri (resource, "rdf:type", "nmm:Photo");
                }
        }
 
        if (!gst_tag_list_is_empty (extractor->tagcache)) {
                GList *node;
-               gchar *performer_uri = NULL;
-               gchar *composer_uri = NULL;
-               gchar *album_artist_uri = NULL;
-               gchar *album_uri = NULL;
-               gchar *album_disc_uri = NULL;
+               TrackerResource *equipment;
+               TrackerResource *geolocation, *address;
+               TrackerResource *performer = NULL, *composer = NULL;
+               TrackerResource *album_disc;
 
                extractor_apply_general_metadata (extractor,
                                                  extractor->tagcache,
                                                  file_url,
-                                                 preupdate,
-                                                 metadata,
-                                                 graph,
-                                                 &performer_uri,
-                                                 &composer_uri);
-
-               extractor_apply_device_metadata (extractor,
-                                                extractor->tagcache,
-                                                preupdate,
-                                                metadata,
-                                                graph);
-
-               extractor_apply_geolocation_metadata (extractor,
-                                                     extractor->tagcache,
-                                                     preupdate,
-                                                     metadata,
-                                                     graph);
+                                                 resource,
+                                                 &performer,
+                                                 &composer);
+
+               equipment = extractor_get_equipment (extractor, extractor->tagcache);
+               if (equipment) {
+                       tracker_resource_set_relation (resource, "nfo:equipment", equipment);
+                       g_object_unref (equipment);
+               }
+
+               geolocation = extractor_get_geolocation (extractor, extractor->tagcache);
+               if (geolocation) {
+                       tracker_resource_set_relation (resource, "slo:location", geolocation);
+                       g_object_unref (geolocation);
+               }
+
+               address = extractor_get_address (extractor, extractor->tagcache);
+               if (address) {
+                       tracker_resource_set_relation (resource, "slo:postalAddress", address);
+                       g_object_unref (address);
+               }
 
                if (extractor->mime == EXTRACT_MIME_VIDEO) {
                        extractor_apply_video_metadata (extractor,
                                                        extractor->tagcache,
-                                                       metadata,
-                                                       performer_uri,
-                                                       composer_uri);
+                                                       resource,
+                                                       performer,
+                                                       composer);
                }
 
                if (extractor->mime == EXTRACT_MIME_AUDIO) {
-                       extractor_apply_album_metadata (extractor,
-                                                       extractor->tagcache,
-                                                       preupdate,
-                                                       graph,
-                                                       &album_artist_uri,
-                                                       &album_uri,
-                                                       &album_disc_uri);
+                       album_disc = extractor_maybe_get_album_disc (extractor, extractor->tagcache);
 
                        extractor_apply_audio_metadata (extractor,
                                                        extractor->tagcache,
-                                                       metadata,
-                                                       performer_uri,
-                                                       composer_uri,
-                                                       album_uri,
-                                                       album_disc_uri);
+                                                       resource,
+                                                       performer,
+                                                       composer,
+                                                       album_disc);
 
                        /* If the audio file contains multiple tracks, we create the tracks
                         * as abstract information element types and relate them to the
                         * concrete nfo:FileDataObject using nie:isStoredAs.
                         */
                        if (extractor->toc && g_list_length (extractor->toc->entry_list) > 1) {
-                               delete_existing_tracks (postupdate, graph, file_url);
-
-                               tracker_sparql_builder_insert_open (postupdate, NULL);
-                               if (graph) {
-                                       tracker_sparql_builder_graph_open (postupdate, graph);
-                               }
+                               for (node = extractor->toc->entry_list; node; node = node->next) {
+                                       TrackerResource *track;
 
-                               for (node = extractor->toc->entry_list; node; node = node->next)
-                                       extract_track_metadata (extractor,
-                                                               node->data,
-                                                               file_url,
-                                                               preupdate,
-                                                               postupdate,
-                                                               graph,
-                                                               album_uri,
-                                                               album_disc_uri);
-
-                               if (graph) {
-                                       tracker_sparql_builder_graph_close (postupdate);
+                                       track = extract_track (extractor, node->data, file_url, album_disc);
+                                       tracker_resource_set_relation (track, "nie:isStoredAs", resource);
+                                       g_object_unref (track);
                                }
-                               tracker_sparql_builder_insert_close (postupdate);
 
-                               tracker_sparql_builder_where_open (postupdate);
-                               tracker_sparql_builder_subject_variable (postupdate, "file");
-                               tracker_sparql_builder_predicate (postupdate, "nie:url");
-                               tracker_sparql_builder_object_string (postupdate, file_url);
-                               tracker_sparql_builder_where_close (postupdate);
+                               tracker_resource_set_string (resource, "nie:url", file_url);
                        }
-               }
 
-               g_free (performer_uri);
-               g_free (composer_uri);
-               g_free (album_uri);
-               g_free (album_disc_uri);
-               g_free (album_artist_uri);
+                       if (album_disc)
+                               g_object_unref (album_disc);
+               }
        }
 
        /* OpenSubtitles compatible hash */
@@ -1361,37 +1039,36 @@ extract_metadata (MetadataExtractor      *extractor,
                g_object_unref (file);
 
                if (hash) {
+                       TrackerResource *hash_resource;
                        char *hash_str;
 
-                       /* { <foo> a nfo:FileHash; nfo:hashValue "..."; nfo:hashAlgorithm "gibest" } */
-                       tracker_sparql_builder_predicate (metadata, "nfo:hasHash");
-
-                       tracker_sparql_builder_object_blank_open (metadata);
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nfo:FileHash");
+                       hash_resource = tracker_resource_new (NULL);
+                       tracker_resource_set_uri (hash_resource, "rdf:type", "nfo:FileHash");
 
-                       tracker_sparql_builder_predicate (metadata, "nfo:hashValue");
                        hash_str = g_strdup_printf ("%" G_GINT64_MODIFIER "x", hash);
-                       tracker_sparql_builder_object_string (metadata, hash_str);
+                       tracker_resource_set_string (hash_resource, "nfo:hashValue", hash_str);
                        g_free (hash_str);
 
-                       tracker_sparql_builder_predicate (metadata, "nfo:hashAlgorithm");
-                       tracker_sparql_builder_object_string (metadata, "gibest");
+                       tracker_resource_set_string (hash_resource, "nfo:hashAlgorithm", "gibest");
 
-                       tracker_sparql_builder_object_blank_close (metadata);
+                       tracker_resource_set_relation (resource, "nfo:hasHash", hash_resource);
+
+                       g_object_unref (hash_resource);
                }
        }
 
        /* If content was encrypted, set it. */
 /* #warning TODO: handle encrypted content with the Discoverer/GUPnP-DLNA backends */
 
-       common_extract_stream_metadata (extractor, file_url, metadata);
+       common_extract_stream_metadata (extractor, file_url, resource);
 
 #ifdef HAVE_LIBMEDIAART
        if (extractor->mime == EXTRACT_MIME_AUDIO) {
                get_embedded_media_art (extractor);
        }
 #endif
+
+       return resource;
 }
 
 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \
@@ -1399,30 +1076,26 @@ extract_metadata (MetadataExtractor      *extractor,
 static void
 common_extract_stream_metadata (MetadataExtractor    *extractor,
                                 const gchar          *uri,
-                                TrackerSparqlBuilder *metadata)
+                                TrackerResource      *resource)
 {
        if (extractor->mime == EXTRACT_MIME_AUDIO ||
            extractor->mime == EXTRACT_MIME_VIDEO) {
                if (extractor->audio_channels >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:channels");
-                       tracker_sparql_builder_object_int64 (metadata, extractor->audio_channels);
+                       tracker_resource_set_int64 (resource, "nfo:channels", extractor->audio_channels);
                }
 
                if (extractor->audio_samplerate >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
-                       tracker_sparql_builder_object_int64 (metadata, extractor->audio_samplerate);
+                       tracker_resource_set_int64 (resource, "nfo:sampleRate", extractor->audio_samplerate);
                }
 
                if (extractor->duration >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:duration");
-                       tracker_sparql_builder_object_int64 (metadata, extractor->duration);
+                       tracker_resource_set_int64 (resource, "nfo:duration", extractor->duration);
                }
        }
 
        if (extractor->mime == EXTRACT_MIME_VIDEO) {
                if (extractor->video_fps >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:frameRate");
-                       tracker_sparql_builder_object_double (metadata, (gdouble)extractor->video_fps);
+                       tracker_resource_set_double (resource, "nfo:frameRate", 
(gdouble)extractor->video_fps);
                }
        }
 
@@ -1430,32 +1103,27 @@ common_extract_stream_metadata (MetadataExtractor    *extractor,
            extractor->mime == EXTRACT_MIME_VIDEO) {
 
                if (extractor->width >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:width");
-                       tracker_sparql_builder_object_int64 (metadata, extractor->width);
+                       tracker_resource_set_int64 (resource, "nfo:width", extractor->width);
                }
 
                if (extractor->height >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:height");
-                       tracker_sparql_builder_object_int64 (metadata, extractor->height);
+                       tracker_resource_set_int64 (resource, "nfo:height", extractor->height);
                }
 
                if (extractor->aspect_ratio >= 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:aspectRatio");
-                       tracker_sparql_builder_object_double (metadata, (gdouble)extractor->aspect_ratio);
+                       tracker_resource_set_double (resource, "nfo:aspectRatio", 
(gdouble)extractor->aspect_ratio);
                }
        }
 
 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA)
        if (extractor->dlna_profile) {
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
-               tracker_sparql_builder_object_string (metadata, extractor->dlna_profile);
+               tracker_resource_set_string (resource, "nmm:dlnaProfile", extractor->dlna_profile);
        } else {
                g_debug ("No DLNA profile found");
        }
 
        if (extractor->dlna_mime) {
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
-               tracker_sparql_builder_object_string (metadata, extractor->dlna_mime);
+               tracker_resource_set_string (resource, "nmm:dlnaMime", extractor->dlna_mime);
        } else {
                g_debug ("No DLNA mime found");
        }
@@ -1653,13 +1321,12 @@ discoverer_init_and_run (MetadataExtractor *extractor,
 #endif /* defined(GSTREAMER_BACKEND_DISCOVERER) || \
           defined(GSTREAMER_BACKEND_GUPNP_DLNA) */
 
-static void
+static TrackerResource *
 tracker_extract_gstreamer (const gchar          *uri,
                            TrackerExtractInfo   *info,
-                           ExtractMime           type,
-                           const gchar          *graph)
+                           ExtractMime           type)
 {
-       TrackerSparqlBuilder *metadata, *preupdate, *postupdate;
+       TrackerResource *main_resource = NULL;
        MetadataExtractor *extractor;
        GstBuffer *buffer;
        gchar *cue_sheet;
@@ -1669,14 +1336,7 @@ tracker_extract_gstreamer (const gchar          *uri,
        MediaArtProcess *media_art_process;
 #endif
 
-       g_return_if_fail (uri);
-
-       graph = tracker_extract_info_get_graph (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       postupdate = tracker_extract_info_get_postupdate_builder (info);
-
-       g_return_if_fail (metadata);
+       g_return_val_if_fail (uri, NULL);
 
        gst_init (NULL, NULL);
 
@@ -1711,12 +1371,7 @@ tracker_extract_gstreamer (const gchar          *uri,
                        extractor->toc = translate_discoverer_toc (extractor->gst_toc);
                }
 
-               extract_metadata (extractor,
-                                 uri,
-                                 preupdate,
-                                 postupdate,
-                                 metadata,
-                                 graph);
+               main_resource = extract_metadata (extractor, uri);
 
 #ifdef HAVE_LIBMEDIAART
                if (extractor->media_art_type != MEDIA_ART_NONE &&
@@ -1777,12 +1432,14 @@ tracker_extract_gstreamer (const gchar          *uri,
        if (extractor->gst_toc)
                gst_toc_unref (extractor->gst_toc);
 
-       g_slist_foreach (extractor->artist_list, (GFunc)g_free, NULL);
+       g_slist_foreach (extractor->artist_list, (GFunc)g_object_unref, NULL);
        g_slist_free (extractor->artist_list);
 
        discoverer_shutdown (extractor);
 
        g_slice_free (MetadataExtractor, extractor);
+
+       return main_resource;
 }
 
 G_MODULE_EXPORT gboolean
@@ -1790,17 +1447,16 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
        GFile *file;
        gchar *uri;
-       const gchar *graph;
        const gchar *mimetype;
+       TrackerResource *main_resource;
 
        file = tracker_extract_info_get_file (info);
        uri = g_file_get_uri (file);
-       graph = tracker_extract_info_get_graph (info);
        mimetype = tracker_extract_info_get_mimetype (info);
 
 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA)
        if (g_str_has_prefix (mimetype, "dlna/")) {
-               tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS, graph);
+               main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS);
        } else
 #endif /* GSTREAMER_BACKEND_GUPNP_DLNA */
 
@@ -1809,18 +1465,23 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                    strcmp (mimetype, "video/x-ms-asf") == 0 ||
                    strcmp (mimetype, "application/vnd.ms-asf") == 0 ||
                   strcmp (mimetype, "application/vnd.rn-realmedia") == 0) {
-               tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS, graph);
+               main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS);
        } else if (g_str_has_prefix (mimetype, "audio/")) {
-               tracker_extract_gstreamer (uri, info, EXTRACT_MIME_AUDIO, graph);
+               main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_AUDIO);
        } else if (g_str_has_prefix (mimetype, "video/")) {
-               tracker_extract_gstreamer (uri, info, EXTRACT_MIME_VIDEO, graph);
+               main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_VIDEO);
        } else if (g_str_has_prefix (mimetype, "image/")) {
-               tracker_extract_gstreamer (uri, info, EXTRACT_MIME_IMAGE, graph);
+               main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_IMAGE);
        } else {
                g_free (uri);
                return FALSE;
        }
 
+       if (main_resource) {
+               tracker_extract_info_set_resource (info, main_resource);
+               g_object_unref (main_resource);
+       }
+
        g_free (uri);
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-html.c b/src/tracker-extract/tracker-extract-html.c
index 29033c6..497f009 100644
--- a/src/tracker-extract/tracker-extract-html.c
+++ b/src/tracker-extract/tracker-extract-html.c
@@ -36,7 +36,7 @@ typedef enum {
 } tag_type;
 
 typedef struct {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        tag_type current;
        guint in_body : 1;
        guint has_license : 1;
@@ -112,8 +112,7 @@ parser_start_element (void           *data,
                        href = lookup_attribute (attrs, "href");
 
                        if (href && !pd->has_license) {
-                               tracker_sparql_builder_predicate (pd->metadata, "nie:license");
-                               tracker_sparql_builder_object_unvalidated (pd->metadata, href);
+                               tracker_resource_add_string (pd->metadata, "nie:license", href);
                                pd->has_license = TRUE;
                        }
                }
@@ -126,13 +125,11 @@ parser_start_element (void           *data,
                        author = lookup_attribute (attrs, "content");
 
                        if (author) {
-                               tracker_sparql_builder_predicate (pd->metadata, "nco:creator");
-                               tracker_sparql_builder_object_blank_open (pd->metadata);
-                               tracker_sparql_builder_predicate (pd->metadata, "a");
-                               tracker_sparql_builder_object (pd->metadata, "nco:Contact");
-                               tracker_sparql_builder_predicate (pd->metadata, "nco:fullname");
-                               tracker_sparql_builder_object_unvalidated (pd->metadata, author);
-                               tracker_sparql_builder_object_blank_close (pd->metadata);
+                               TrackerResource *creator = tracker_extract_new_contact (author);
+
+                               tracker_resource_add_relation (pd->metadata, "nco:creator", creator);
+
+                               g_object_unref (creator);
                        }
                }
 
@@ -142,8 +139,7 @@ parser_start_element (void           *data,
                        desc = lookup_attribute (attrs,"content");
 
                        if (desc && !pd->has_description) {
-                               tracker_sparql_builder_predicate (pd->metadata, "nie:description");
-                               tracker_sparql_builder_object_unvalidated (pd->metadata, desc);
+                               tracker_resource_set_string (pd->metadata, "nie:description", desc);
                                pd->has_description = TRUE;
                        }
                }
@@ -162,8 +158,7 @@ parser_start_element (void           *data,
                                                        continue;
                                                }
 
-                                               tracker_sparql_builder_predicate (pd->metadata, 
"nie:keyword");
-                                               tracker_sparql_builder_object_unvalidated (pd->metadata, 
g_strstrip (keywords[i]));
+                                               tracker_resource_add_string (pd->metadata, "nie:keyword", 
g_strstrip (keywords[i]));
                                        }
 
                                        g_strfreev (keywords);
@@ -236,7 +231,7 @@ parser_characters (void          *data,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        GFile *file;
        TrackerConfig *config;
        htmlDocPtr doc;
@@ -277,11 +272,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                NULL  /* xmlStructuredErrorFunc */
        };
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
        file = tracker_extract_info_get_file (info);
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:HtmlDocument");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:HtmlDocument");
 
        pd.metadata = metadata;
        pd.current = -1;
@@ -305,18 +299,19 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        if (pd.title->str &&
            *pd.title->str != '\0') {
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_unvalidated (metadata, pd.title->str);
+               tracker_resource_set_string (metadata, "nie:title", pd.title->str);
        }
 
        if (pd.plain_text->str &&
            *pd.plain_text->str != '\0') {
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, pd.plain_text->str);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", pd.plain_text->str);
        }
 
        g_string_free (pd.plain_text, TRUE);
        g_string_free (pd.title, TRUE);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-icon.c b/src/tracker-extract/tracker-extract-icon.c
index c24d524..4f7dfa4 100644
--- a/src/tracker-extract/tracker-extract-icon.c
+++ b/src/tracker-extract/tracker-extract-icon.c
@@ -127,35 +127,36 @@ find_max_width_and_height (const gchar *uri,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        guint max_width;
        guint max_height;
        GFile *file;
        gchar *uri;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
        file = tracker_extract_info_get_file (info);
        uri = g_file_get_uri (file);
 
+       metadata = tracker_resource_new (NULL);
+
        /* The Windows Icon file format may contain the same icon with different
         * sizes inside, so there's no clear way of setting single width and
         * height values. Thus, we set maximum sizes found. */
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_object (metadata, "nfo:Icon");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Icon");
 
        if (find_max_width_and_height (uri, &max_width, &max_height)) {
                if (max_width > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:width");
-                       tracker_sparql_builder_object_int64 (metadata, (gint64) max_width);
+                       tracker_resource_set_int64 (metadata, "nfo:width", (gint64)max_width);
                }
                if (max_height > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:height");
-                       tracker_sparql_builder_object_int64 (metadata, (gint64) max_height);
+                       tracker_resource_set_int64 (metadata, "nfo:height", (gint64)max_height);
                }
        }
 
        g_free (uri);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-iso.c b/src/tracker-extract/tracker-extract-iso.c
index eeaadb6..66f3c62 100644
--- a/src/tracker-extract/tracker-extract-iso.c
+++ b/src/tracker-extract/tracker-extract-iso.c
@@ -35,7 +35,7 @@ G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info_)
 {
        /* NOTE: This function has to exist, tracker-extract checks
-        * the symbole table for this function and if it doesn't
+        * the symbol table for this function and if it doesn't
         * exist, the module is not loaded to be used as an extractor.
         */
 
@@ -53,17 +53,18 @@ tracker_extract_get_metadata (TrackerExtractInfo *info_)
        gboolean bootable;
        const gchar *id;
        const gchar *name;
-        GList *languages, *l;
-       TrackerSparqlBuilder *metadata;
-
-       metadata = tracker_extract_info_get_metadata_builder (info_);
+       GList *languages, *l;
+       TrackerResource *metadata;
 
        file = tracker_extract_info_get_file (info_);
        filename = g_file_get_path (file);
 
+       metadata = tracker_resource_new (NULL);
+
        media = osinfo_media_create_from_location (filename, NULL, &error);
        if (error != NULL) {
                if (error->code != OSINFO_MEDIA_ERROR_NOT_BOOTABLE) {
+                       g_object_unref (metadata);
                        g_message ("Could not extract iso info from '%s': %s",
                                   filename, error->message);
                        g_free (filename);
@@ -95,8 +96,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info_)
        if (os == NULL)
                goto unknown_os;
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:FilesystemImage");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:FilesystemImage");
 
        variants = osinfo_media_get_os_variants (media);
        if (osinfo_list_get_length (OSINFO_LIST (variants)) > 0) {
@@ -110,45 +110,41 @@ tracker_extract_get_metadata (TrackerExtractInfo *info_)
        }
 
        if (name != NULL) {
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_string (metadata, name);
+               tracker_resource_set_string (metadata, "nie:title", name);
        }
 
        if (osinfo_media_get_live (media)) {
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nfo:OperatingSystem");
+               tracker_resource_add_uri (metadata, "rdf:type", "nfo:OperatingSystem");
        }
 
        if (osinfo_media_get_installer (media)) {
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "osinfo:Installer");
+               tracker_resource_add_uri (metadata, "rdf:type", "osinfo:Installer");
        }
 
-       tracker_sparql_builder_predicate (metadata, "nfo:isBootable");
-       tracker_sparql_builder_object_boolean (metadata, bootable);
+       tracker_resource_set_boolean (metadata, "nfo:isBootable", bootable);
 
        id = osinfo_entity_get_id (OSINFO_ENTITY (os));
        if (id != NULL) {
-               tracker_sparql_builder_predicate (metadata, "osinfo:id");
-               tracker_sparql_builder_object_string (metadata, id);
+               tracker_resource_set_string (metadata, "osinfo:id", id);
        }
 
         id = osinfo_entity_get_id (OSINFO_ENTITY (media));
        if (id != NULL) {
-               tracker_sparql_builder_predicate (metadata, "osinfo:mediaId");
-               tracker_sparql_builder_object_string (metadata, id);
+               tracker_resource_set_string (metadata, "osinfo:mediaId", id);
        }
 
         languages = osinfo_media_get_languages (media);
         for (l = languages; l != NULL; l = l->next) {
-               tracker_sparql_builder_predicate (metadata, "osinfo:language");
-               tracker_sparql_builder_object_string (metadata, (char *) l->data);
+               tracker_resource_add_string (metadata, "osinfo:language", (char *)l->data);
         }
         g_list_free (languages);
 
        g_object_unref (G_OBJECT (media));
        g_object_unref (G_OBJECT (loader));
 
+       tracker_extract_info_set_resource (info_, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 
 unknown_os:
@@ -157,8 +153,7 @@ unknown_os:
                 gchar *stripped = g_strdup (name);
 
                 g_strstrip (stripped);
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_string (metadata, stripped);
+               tracker_resource_set_string (metadata, "nie:title", stripped);
                 g_free (stripped);
        }
 
@@ -170,11 +165,12 @@ no_os:
                g_object_unref (G_OBJECT (loader));
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:FilesystemImage");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:FilesystemImage");
+
+       tracker_resource_set_boolean (metadata, "nfo:isBootable", bootable);
 
-       tracker_sparql_builder_predicate (metadata, "nfo:isBootable");
-       tracker_sparql_builder_object_boolean (metadata, bootable);
+       tracker_extract_info_set_resource (info_, metadata);
+       g_object_unref (metadata);
 
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-jpeg.c b/src/tracker-extract/tracker-extract-jpeg.c
index a9f8f6e..03ab269 100644
--- a/src/tracker-extract/tracker-extract-jpeg.c
+++ b/src/tracker-extract/tracker-extract-jpeg.c
@@ -135,7 +135,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        struct jpeg_decompress_struct cinfo;
        struct tej_error_mgr tejerr;
        struct jpeg_marker_struct *marker;
-       TrackerSparqlBuilder *preupdate, *metadata;
+       TrackerResource *metadata;
        TrackerXmpData *xd = NULL;
        TrackerExifData *ed = NULL;
        TrackerIptcData *id = NULL;
@@ -145,16 +145,11 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        goffset size;
        gchar *filename, *uri;
        gchar *comment = NULL;
-       const gchar *dlna_profile, *dlna_mimetype, *graph, *urn;
+       const gchar *dlna_profile, *dlna_mimetype;
        GPtrArray *keywords;
        gboolean success = TRUE;
        guint i;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-       urn = tracker_extract_info_get_urn (info);
-
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
 
@@ -174,11 +169,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        uri = g_file_get_uri (file);
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nmm:Photo");
-
        cinfo.err = jpeg_std_error (&tejerr.jpeg);
        tejerr.jpeg.error_exit = extract_jpeg_error_exit;
        if (setjmp (tejerr.setjmp_buffer)) {
@@ -186,6 +176,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                goto fail;
        }
 
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:Photo");
+
        jpeg_create_decompress (&cinfo);
 
        jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF);
@@ -304,43 +298,18 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        md.model = tracker_coalesce_strip (2, xd->model, ed->model);
 
        /* Prioritize on native dimention in all cases */
-       tracker_sparql_builder_predicate (metadata, "nfo:width");
-       tracker_sparql_builder_object_int64 (metadata, cinfo.image_width);
-
-       /* TODO: add ontology and store ed->software */
-
-       tracker_sparql_builder_predicate (metadata, "nfo:height");
-       tracker_sparql_builder_object_int64 (metadata, cinfo.image_height);
+       tracker_resource_set_int64 (metadata, "nfo:width", cinfo.image_width);
+       tracker_resource_set_int64 (metadata, "nfo:height", cinfo.image_height);
 
        if (guess_dlna_profile (cinfo.image_width, cinfo.image_height, &dlna_profile, &dlna_mimetype)) {
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
-               tracker_sparql_builder_object_string (metadata, dlna_profile);
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
-               tracker_sparql_builder_object_string (metadata, dlna_mimetype);
+               tracker_resource_set_string (metadata, "nmm:dlnaProfile", dlna_profile);
+               tracker_resource_set_string (metadata, "nmm:dlnaMime", dlna_mimetype);
        }
 
        if (id->contact) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", id->contact);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, id->contact);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               TrackerResource *contact = tracker_extract_new_contact (id->contact);
+               tracker_resource_add_relation (metadata, "nco:contributor", contact);
+               g_object_unref (contact);
        }
 
        keywords = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
@@ -358,274 +327,147 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (xd->publisher) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:publisher");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               TrackerResource *publisher = tracker_extract_new_contact (xd->publisher);
+               tracker_resource_add_relation (metadata, "nco:publisher", publisher);
+               g_object_unref (publisher);
        }
 
        if (xd->type) {
-               tracker_sparql_builder_predicate (metadata, "dc:type");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->type);
+               tracker_resource_set_string (metadata, "dc:type", xd->type);
        }
 
        if (xd->rating) {
-               tracker_sparql_builder_predicate (metadata, "nao:numericRating");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
+               tracker_resource_set_string (metadata, "nao:numericRating", xd->rating);
        }
 
        if (xd->format) {
-               tracker_sparql_builder_predicate (metadata, "dc:format");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->format);
+               tracker_resource_set_string (metadata, "dc:format", xd->format);
        }
 
        if (xd->identifier) {
-               tracker_sparql_builder_predicate (metadata, "dc:identifier");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
+               tracker_resource_set_string (metadata, "dc:identifier", xd->identifier);
        }
 
        if (xd->source) {
-               tracker_sparql_builder_predicate (metadata, "dc:source");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->source);
+               tracker_resource_set_string (metadata, "dc:source", xd->source);
        }
 
        if (xd->language) {
-               tracker_sparql_builder_predicate (metadata, "dc:language");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->language);
+               tracker_resource_set_string (metadata, "dc:language", xd->language);
        }
 
        if (xd->relation) {
-               tracker_sparql_builder_predicate (metadata, "dc:relation");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
+               tracker_resource_set_string (metadata, "dc:relation", xd->relation);
        }
 
        if (xd->coverage) {
-               tracker_sparql_builder_predicate (metadata, "dc:coverage");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
+               tracker_resource_set_string (metadata, "dc:coverage", xd->coverage);
        }
 
        if (xd->license) {
-               tracker_sparql_builder_predicate (metadata, "nie:license");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->license);
+               tracker_resource_set_string (metadata, "nie:license", xd->license);
        }
 
-        if (xd->regions) {
-               tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
-        }
+       if (xd->regions) {
+               tracker_xmp_apply_regions_to_resource (metadata, xd);
+       }
 
        if (id->keywords) {
                tracker_keywords_parse (keywords, id->keywords);
        }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *escaped, *subject;
+               TrackerResource *tag;
                const gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               subject = g_strdup_printf ("_:tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject (preupdate, subject);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_append (preupdate,
-                                              "WHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
-
-               /* associate file with tag */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject_iri (preupdate, urn);
-               tracker_sparql_builder_predicate (preupdate, "nao:hasTag");
-               tracker_sparql_builder_object (preupdate, "?tag");
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject (preupdate, "?tag");
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_where_close (preupdate);
-
-               g_free (subject);
-               g_free (escaped);
+               tag = tracker_extract_new_tag (p);
+
+               tracker_resource_add_relation (metadata, "nao:hasTag", tag);
+
+               g_object_unref (tag);
        }
        g_ptr_array_free (keywords, TRUE);
 
        if (md.make || md.model) {
-               gchar *equip_uri;
-
-               equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                             md.make ? md.make : "",
-                                                             md.model ? md.model : "");
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:Equipment");
-
-               if (md.make) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.make);
-               }
-               if (md.model) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.model);
-               }
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-               tracker_sparql_builder_object_iri (metadata, equip_uri);
-               g_free (equip_uri);
+               TrackerResource *equipment = tracker_extract_new_equipment (md.make, md.model);
+               tracker_resource_add_relation (metadata, "nfo:equipment", equipment);
+               g_object_unref (equipment);
        }
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          md.title,
-                                          uri,
-                                          NULL);
+       tracker_guarantee_resource_title_from_file (metadata,
+                                                   "nie:title",
+                                                   md.title,
+                                                   uri,
+                                                   NULL);
 
        if (md.orientation) {
-               tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-               tracker_sparql_builder_object (metadata, md.orientation);
+               tracker_resource_set_string (metadata, "nfo:orientation", md.orientation);
        }
 
        if (md.copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
+               tracker_resource_set_string (metadata, "nie:copyright", md.copyright);
        }
 
        if (md.white_balance) {
-               tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-               tracker_sparql_builder_object (metadata, md.white_balance);
+               tracker_resource_set_string (metadata, "nmm:whiteBalance", md.white_balance);
        }
 
        if (md.fnumber) {
                gdouble value;
 
                value = g_strtod (md.fnumber, NULL);
-               tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nmm:fnumber", value);
        }
 
        if (md.flash) {
-               tracker_sparql_builder_predicate (metadata, "nmm:flash");
-               tracker_sparql_builder_object (metadata, md.flash);
+               tracker_resource_set_string (metadata, "nmm:flash", md.flash);
        }
 
        if (md.focal_length) {
                gdouble value;
 
                value = g_strtod (md.focal_length, NULL);
-               tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nmm:focalLength", value);
        }
 
        if (md.artist) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               TrackerResource *artist = tracker_extract_new_contact (md.artist);
+               tracker_resource_add_relation (metadata, "nco:contributor", artist);
+               g_object_unref (artist);
        }
 
        if (md.exposure_time) {
                gdouble value;
 
                value = g_strtod (md.exposure_time, NULL);
-               tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nmm:exposureTime", value);
        }
 
        if (md.iso_speed_ratings) {
                gdouble value;
 
                value = g_strtod (md.iso_speed_ratings, NULL);
-               tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nmm:isoSpeed", value);
        }
 
-       tracker_guarantee_date_from_file_mtime (metadata,
-                                               "nie:contentCreated",
-                                               md.date,
-                                               uri);
+       tracker_guarantee_resource_date_from_file_mtime (metadata,
+                                                        "nie:contentCreated",
+                                                        md.date,
+                                                        uri);
 
        if (md.description) {
-               tracker_sparql_builder_predicate (metadata, "nie:description");
-               tracker_sparql_builder_object_unvalidated (metadata, md.description);
+               tracker_resource_set_string(metadata, "nie:description", md.description);
        }
 
        if (md.metering_mode) {
-               tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-               tracker_sparql_builder_object (metadata, md.metering_mode);
+               tracker_resource_set_string(metadata, "nmm:meteringMode", md.metering_mode);
        }
 
        if (md.creator) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               TrackerResource *creator = tracker_extract_new_contact (md.creator);
+               tracker_resource_add_relation (metadata, "nco:creator", creator);
+               g_object_unref (creator);
 
                /* NOTE: We only have affiliation with
                 * nco:PersonContact and we are using
@@ -649,93 +491,26 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                /*      tracker_sparql_builder_predicate (preupdate, "nco:hasAffiliation"); */
                /*      tracker_sparql_builder_object (preupdate, "_:affiliation_by_line"); */
                /* } */
-
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
        }
 
        if (md.comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, md.comment);
+               tracker_resource_set_string (metadata, "nie:comment", md.comment);
        }
 
        if (md.address || md.state || md.country || md.city ||
            md.gps_altitude || md.gps_latitude || md.gps_longitude) {
 
-               tracker_sparql_builder_predicate (metadata, "slo:location");
-
-               tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
-
-               if (md.address || md.state || md.country || md.city) {
-                       gchar *addruri;
-
-                       addruri = tracker_sparql_get_uuid_urn ();
-
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, addruri);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, addruri);
-
-                       g_free (addruri);
-
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
+               TrackerResource *location = tracker_extract_new_location (md.address,
+                       md.state, md.city, md.country, md.gps_altitude,
+                       md.gps_latitude, md.gps_longitude);
 
-                       if (md.address) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.address);
-                       }
-
-                       if (md.state) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:region");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.state);
-                       }
-
-                       if (md.city) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.city);
-                       }
+               tracker_resource_add_relation (metadata, "slo:location", location);
 
-                       if (md.country) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:country");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.country);
-                       }
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-
-               if (md.gps_altitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_altitude);
-               }
-
-               if (md.gps_latitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_latitude);
-               }
-
-               if (md.gps_longitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_longitude);
-               }
-
-               tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+               g_object_unref (location);
        }
 
        if (md.gps_direction) {
-               tracker_sparql_builder_predicate (metadata, "nfo:heading");
-               tracker_sparql_builder_object_unvalidated (metadata, md.gps_direction);
+               tracker_resource_set_string (metadata, "nfo:heading", md.gps_direction);
        }
 
        if (cinfo.density_unit != 0 || ed->x_resolution) {
@@ -753,8 +528,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                value = cinfo.X_density * CM_TO_INCH;
                }
 
-               tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:horizontalResolution", value);
        }
 
        if (cinfo.density_unit != 0 || ed->y_resolution) {
@@ -772,8 +546,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                value = cinfo.Y_density * CM_TO_INCH;
                }
 
-               tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:verticalResolution", value);
        }
 
        jpeg_destroy_decompress (&cinfo);
@@ -783,6 +556,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        tracker_iptc_free (id);
        g_free (comment);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
 fail:
        tracker_file_close (f, FALSE);
        g_free (uri);
diff --git a/src/tracker-extract/tracker-extract-libav.c b/src/tracker-extract/tracker-extract-libav.c
index 500d7d8..cd8147b 100644
--- a/src/tracker-extract/tracker-extract-libav.c
+++ b/src/tracker-extract/tracker-extract-libav.c
@@ -34,107 +34,12 @@
 #include <libavformat/avformat.h>
 #include <libavutil/mathematics.h>
 
-static void
-open_insert (TrackerSparqlBuilder *preupdate,
-             const char           *graph,
-             const gchar          *iri,
-             const gchar          *type)
-{
-       tracker_sparql_builder_insert_open (preupdate, NULL);
-       if (graph) {
-               tracker_sparql_builder_graph_open (preupdate, graph);
-       }
-
-       tracker_sparql_builder_subject_iri (preupdate, iri);
-       tracker_sparql_builder_predicate (preupdate, "a");
-       tracker_sparql_builder_object (preupdate, type);
-}
-
-static void
-close_insert (TrackerSparqlBuilder *preupdate, const char *graph)
-{
-       if (graph) {
-               tracker_sparql_builder_graph_close (preupdate);
-       }
-       tracker_sparql_builder_insert_close (preupdate);
-}
-
-static void
-delete_value (TrackerSparqlBuilder *preupdate,
-              const gchar          *iri,
-              const gchar          *predicate,
-              const char           *value)
-{
-       tracker_sparql_builder_delete_open (preupdate, NULL);
-       tracker_sparql_builder_subject_iri (preupdate, iri);
-       tracker_sparql_builder_predicate (preupdate, predicate);
-       tracker_sparql_builder_object_variable (preupdate, value);
-       tracker_sparql_builder_delete_close (preupdate);
-
-       tracker_sparql_builder_where_open (preupdate);
-       tracker_sparql_builder_subject_iri (preupdate, iri);
-       tracker_sparql_builder_predicate (preupdate, predicate);
-       tracker_sparql_builder_object_variable (preupdate, value);
-       tracker_sparql_builder_where_close (preupdate);
-}
-
-static void
-set_value_iri (TrackerSparqlBuilder *metadata,
-               const gchar          *predicate,
-               const gchar          *iri)
-{
-       tracker_sparql_builder_predicate (metadata, predicate);
-       tracker_sparql_builder_object_iri (metadata, iri);
-}
-
-static void
-set_value_double (TrackerSparqlBuilder *metadata,
-                  const gchar          *predicate,
-                  gdouble               value)
-{
-       tracker_sparql_builder_predicate (metadata, predicate);
-       tracker_sparql_builder_object_double (metadata, value);
-}
-
-static void
-set_value_int64 (TrackerSparqlBuilder *metadata,
-                 const gchar          *predicate,
-                 gint64                value)
-{
-       tracker_sparql_builder_predicate (metadata, predicate);
-       tracker_sparql_builder_object_int64 (metadata, value);
-}
-
-static void
-set_value_string (TrackerSparqlBuilder *metadata,
-                  const gchar          *predicate,
-                  const gchar          *value)
-{
-       tracker_sparql_builder_predicate (metadata, predicate);
-       tracker_sparql_builder_object_unvalidated (metadata, value);
-}
-
-static gchar *
-create_artist (TrackerSparqlBuilder *preupdate,
-               const gchar          *graph,
-               const char           *name)
-{
-       gchar *uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", name);
-
-       open_insert (preupdate, graph, uri, "nmm:Artist");
-       set_value_string (preupdate, "nmm:artistName", name);
-       close_insert (preupdate, graph);
-
-       return uri;
-}
 
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
        GFile *file;
-       TrackerSparqlBuilder *metadata;
-       TrackerSparqlBuilder *preupdate;
-       const gchar *graph;
+       TrackerResource *metadata;
        gchar *absolute_file_path;
        gchar *uri;
        AVFormatContext *format = NULL;
@@ -148,9 +53,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        av_register_all ();
 
        file = tracker_extract_info_get_file (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       graph = tracker_extract_info_get_graph (info);
 
        uri = g_file_get_uri (file);
 
@@ -180,78 +82,77 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
+       metadata = tracker_resource_new (NULL);
+
        if (audio_stream) {
                if (audio_stream->codec->sample_rate > 0) {
-                       set_value_int64 (metadata, "nfo:sampleRate", audio_stream->codec->sample_rate);
+                       tracker_resource_set_int64 (metadata, "nfo:sampleRate", 
audio_stream->codec->sample_rate);
                }
                if (audio_stream->codec->channels > 0) {
-                       set_value_int64 (metadata, "nfo:channels", audio_stream->codec->channels);
+                       tracker_resource_set_int64 (metadata, "nfo:channels", audio_stream->codec->channels);
                }
        }
 
        if (video_stream) {
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nmm:Video");
+               tracker_resource_add_uri(metadata, "rdf:type", "nmm:Video");
 
                if (video_stream->codec->width > 0 && video_stream->codec->height > 0) {
-                       set_value_int64 (metadata, "nfo:width", video_stream->codec->width);
-                       set_value_int64 (metadata, "nfo:height", video_stream->codec->height);
+                       tracker_resource_set_int64 (metadata, "nfo:width", video_stream->codec->width);
+                       tracker_resource_set_int64 (metadata, "nfo:height", video_stream->codec->height);
                }
 
                if (video_stream->avg_frame_rate.num > 0) {
                        gdouble frame_rate = (gdouble) video_stream->avg_frame_rate.num
                                             / video_stream->avg_frame_rate.den;
-                       set_value_double (metadata, "nfo:frameRate", frame_rate);
+                       tracker_resource_set_double (metadata, "nfo:frameRate", frame_rate);
                }
 
                if (video_stream->duration > 0) {
                        gint64 duration = av_rescale(video_stream->duration, video_stream->time_base.num,
                                                     video_stream->time_base.den);
-                       set_value_int64 (metadata, "nfo:duration", duration);
+                       tracker_resource_set_int64 (metadata, "nfo:duration", duration);
                }
 
                if (video_stream->sample_aspect_ratio.num > 0) {
                        gdouble aspect_ratio = (gdouble) video_stream->sample_aspect_ratio.num
                                               / video_stream->sample_aspect_ratio.den;
-                       set_value_double (metadata, "nfo:aspectRatio", aspect_ratio);
+                       tracker_resource_set_double (metadata, "nfo:aspectRatio", aspect_ratio);
                }
 
                if (video_stream->nb_frames > 0) {
-                       set_value_int64 (metadata, "nfo:frameCount", video_stream->nb_frames);
+                       tracker_resource_set_int64 (metadata, "nfo:frameCount", video_stream->nb_frames);
                }
 
                if ((tag = av_dict_get (format->metadata, "synopsis", NULL, 0))) {
-                       set_value_string (metadata, "nmm:synopsis", tag->value);
+                       tracker_resource_set_string (metadata, "nmm:synopsis", tag->value);
                }
 
                if ((tag = av_dict_get (format->metadata, "episode_sort", NULL, 0))) {
-                       set_value_int64 (metadata, "nmm:episodeNumber", atoi(tag->value));
+                       tracker_resource_set_int64 (metadata, "nmm:episodeNumber", atoi(tag->value));
                }
 
                if ((tag = av_dict_get (format->metadata, "season_number", NULL, 0))) {
-                       set_value_int64 (metadata, "nmm:season", atoi(tag->value));
+                       tracker_resource_set_int64 (metadata, "nmm:season", atoi(tag->value));
                }
 
        } else if (audio_stream) {
-               const char *album_title = NULL;
-               const char *album_artist = NULL;
-               gchar *album_artist_uri = NULL;
-               gchar *performer_uri = NULL;
+               TrackerResource *album_artist = NULL, *performer = NULL;
+               char *album_artist_name = NULL;
+               char *album_title = NULL;
 
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
-               tracker_sparql_builder_object (metadata, "nfo:Audio");
+               tracker_resource_add_uri (metadata, "rdf:type", "nmm:MusicPiece");
+               tracker_resource_add_uri (metadata, "rdf:type", "nfo:Audio");
 
                if (audio_stream->duration > 0) {
                        gint64 duration = av_rescale(audio_stream->duration, audio_stream->time_base.num,
                                                     audio_stream->time_base.den);
-                       set_value_int64 (metadata, "nfo:duration", duration);
+                       tracker_resource_set_int64 (metadata, "nfo:duration", duration);
                }
 
                if ((tag = av_dict_get (format->metadata, "track", NULL, 0))) {
                        int track = atoi(tag->value);
                        if (track > 0) {
-                               set_value_int64 (metadata, "nmm:trackNumber", track);
+                               tracker_resource_set_int64 (metadata, "nmm:trackNumber", track);
                        }
                }
 
@@ -260,73 +161,52 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                }
 
                if (album_title && (tag = av_dict_get (format->metadata, "album_artist", NULL, 0))) {
-                       album_artist_uri = create_artist (preupdate, graph, tag->value);
-                       album_artist = tag->value;
+                       album_artist_name = tag->value;
+                       album_artist = tracker_extract_new_artist (album_artist_name);
                }
 
                if ((tag = av_dict_get (format->metadata, "artist", tag, 0))) {
-                       performer_uri = create_artist (preupdate, graph, tag->value);
+                       performer = tracker_extract_new_artist (tag->value);
                        if (!album_artist) {
-                               album_artist = tag->value;
+                               album_artist_name = tag->value;
+                               album_artist = performer;
                        }
                }
 
-               if (!performer_uri && (tag = av_dict_get (format->metadata, "performer", tag, 0))) {
-                       performer_uri = create_artist (preupdate, graph, tag->value);
+               if (!performer && (tag = av_dict_get (format->metadata, "performer", tag, 0))) {
+                       performer = tracker_extract_new_artist (tag->value);
                        if (!album_artist) {
-                               album_artist = tag->value;
+                               album_artist_name = tag->value;
+                               album_artist = performer;
                        }
                }
 
-               if (performer_uri) {
-                       set_value_iri (metadata, "nmm:performer", performer_uri);
-               } else if (album_artist_uri) {
-                       set_value_iri (metadata, "nmm:performer", album_artist_uri);
+               if (performer) {
+                       tracker_resource_set_relation (metadata, "nmm:performer", performer);
+               } else if (album_artist) {
+                       tracker_resource_set_relation (metadata, "nmm:performer", album_artist);
                }
 
                if ((tag = av_dict_get (format->metadata, "composer", tag, 0))) {
-                       gchar *composer_uri = create_artist (preupdate, graph, tag->value);
-                       set_value_iri (metadata, "nmm:composer", composer_uri);
-                       g_free(composer_uri);
+                       TrackerResource *composer = tracker_extract_new_artist (tag->value);
+                       tracker_resource_set_relation (metadata, "nmm:composer", composer);
+                       g_object_unref (composer);
                }
 
-
                if (album_title) {
-                       int disc = 1;
-                       gchar *disc_uri;
-                       gchar *album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", album_title);
-
-                       open_insert (preupdate, graph, album_uri, "nmm:MusicAlbum");
-                       set_value_string (preupdate, "nmm:albumTitle", album_title);
-                       if (album_artist_uri) {
-                               set_value_iri (preupdate, "nmm:albumArtist", album_artist_uri);
-                       } else if (performer_uri) {
-                               set_value_iri (preupdate, "nmm:albumArtist", performer_uri);
-                       }
-                       close_insert (preupdate, graph);
-
+                       int disc_number = 1;
+                       TrackerResource *album_disc;
 
                        if ((tag = av_dict_get (format->metadata, "disc", NULL, 0))) {
-                               disc = atoi (tag->value);
+                               disc_number = atoi (tag->value);
                        }
 
-                       disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
-                                                                    album_title,
-                                                                    disc);
-
-                       delete_value (preupdate, disc_uri, "nmm:setNumber", "unknown");
-                       delete_value (preupdate, disc_uri, "nmm:albumDiscAlbum", "unknown");
+                       album_disc = tracker_extract_new_music_album_disc (album_title, album_artist, 
disc_number);
 
-                       open_insert (preupdate, graph, disc_uri, "nmm:MusicAlbumDisc");
-                       set_value_int64 (preupdate, "nmm:setNumber", disc);
-                       set_value_iri (preupdate, "nmm:albumDiscAlbum", album_uri);
-                       close_insert (preupdate, graph);
+                       tracker_resource_set_relation (metadata, "nmm:musicAlbumDisc", album_disc);
+                       tracker_resource_set_relation (metadata, "nmm:musicAlbum", 
tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum"));
 
-                       set_value_iri (metadata, "nmm:musicAlbumDisc", disc_uri);
-                       set_value_iri (metadata, "nmm:musicAlbum", album_uri);
-
-                       g_free (disc_uri);
-                       g_free (album_uri);
+                       g_object_unref (album_disc);
                }
 
 #ifdef HAVE_LIBMEDIAART
@@ -353,51 +233,55 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                }
 #endif
 
-               g_free(performer_uri);
+               if (performer)
+                       g_object_unref (performer);
        }
 
        if (format->bit_rate > 0) {
-               set_value_int64 (metadata, "nfo:averageBitrate", format->bit_rate);
+               tracker_resource_set_int64 (metadata, "nfo:averageBitrate", format->bit_rate);
        }
 
 
        if ((tag = av_dict_get (format->metadata, "comment", NULL, 0))) {
-               set_value_string (metadata, "nie:comment", tag->value);
+               tracker_resource_set_string (metadata, "nie:comment", tag->value);
        }
 
        if ((tag = av_dict_get (format->metadata, "copyright", NULL, 0))) {
-               set_value_string (metadata, "nie:copyright", tag->value);
+               tracker_resource_set_string (metadata, "nie:copyright", tag->value);
        }
 
        if ((tag = av_dict_get (format->metadata, "creation_time", NULL, 0))) {
                gchar *content_created = tracker_date_guess (tag->value);
                if (content_created) {
-                       set_value_string (metadata, "nie:contentCreated", content_created);
+                       tracker_resource_set_string (metadata, "nie:contentCreated", content_created);
                        g_free (content_created);
                }
        }
 
        if ((tag = av_dict_get (format->metadata, "description", NULL, 0))) {
-               set_value_string (metadata, "nie:description", tag->value);
+               tracker_resource_set_string (metadata, "nie:description", tag->value);
        }
 
        if ((tag = av_dict_get (format->metadata, "genre", NULL, 0))) {
-               set_value_string (metadata, "nfo:genre", tag->value);
+               tracker_resource_set_string (metadata, "nfo:genre", tag->value);
        }
 
        if ((tag = av_dict_get (format->metadata, "language", NULL, 0))) {
-               set_value_string (metadata, "nfo:language", tag->value);
+               tracker_resource_set_string (metadata, "nfo:language", tag->value);
        }
 
        if ((tag = av_dict_get (format->metadata, "title", NULL, 0))) {
                title = tag->value;
        }
 
-       tracker_guarantee_title_from_file (metadata, "nie:title", title, uri, NULL);
+       tracker_guarantee_resource_title_from_file (metadata, "nie:title", title, uri, NULL);
 
        g_free (uri);
 
        avformat_free_context (format);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-mp3.c b/src/tracker-extract/tracker-extract-mp3.c
index a3e090e..4fe8a9b 100644
--- a/src/tracker-extract/tracker-extract-mp3.c
+++ b/src/tracker-extract/tracker-extract-mp3.c
@@ -151,14 +151,14 @@ typedef struct {
        size_t id3v2_size;
 
        const gchar *title;
-       const gchar *performer;
-       gchar *performer_uri;
-       const gchar *album_artist;
-       gchar *album_artist_uri;
-       const gchar *lyricist;
-       gchar *lyricist_uri;
-       const gchar *album;
-       gchar *album_uri;
+       const gchar *performer_name;
+       TrackerResource *performer;
+       const gchar *album_artist_name;
+       TrackerResource *album_artist;
+       const gchar *lyricist_name;
+       TrackerResource *lyricist;
+       const gchar *album_name;
+       TrackerResource *album;
        const gchar *genre;
        const gchar *text;
        const gchar *recording_time;
@@ -166,8 +166,8 @@ typedef struct {
        const gchar *copyright;
        const gchar *publisher;
        const gchar *comment;
-       const gchar *composer;
-       gchar *composer_uri;
+       const gchar *composer_name;
+       TrackerResource *composer;
        gint track_number;
        gint track_count;
        gint set_number;
@@ -856,7 +856,7 @@ mp3_parse_header (const gchar          *data,
                   size_t                size,
                   size_t                seek_pos,
                   const gchar          *uri,
-                  TrackerSparqlBuilder *metadata,
+                  TrackerResource      *resource,
                   MP3Data              *filedata)
 {
        const gchar *dlna_profile, *dlna_mimetype;
@@ -973,13 +973,11 @@ mp3_parse_header (const gchar          *data,
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "nfo:codec");
-       tracker_sparql_builder_object_string (metadata, "MPEG");
+       tracker_resource_set_string (resource, "nfo:codec", "MPEG");
 
        n_channels = ((header & ch_mask) == ch_mask) ? 1 : 2;
 
-       tracker_sparql_builder_predicate (metadata, "nfo:channels");
-       tracker_sparql_builder_object_int64 (metadata, n_channels);
+       tracker_resource_set_int (resource, "nfo:channels", n_channels);
 
        avg_bps /= frames;
 
@@ -992,21 +990,15 @@ mp3_parse_header (const gchar          *data,
                length = spfp8 * 8 * frames / sample_rate;
        }
 
-       tracker_sparql_builder_predicate (metadata, "nfo:duration");
-       tracker_sparql_builder_object_int64 (metadata, length);
-
-       tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
-       tracker_sparql_builder_object_int64 (metadata, sample_rate);
-       tracker_sparql_builder_predicate (metadata, "nfo:averageBitrate");
-       tracker_sparql_builder_object_int64 (metadata, avg_bps*1000);
+       tracker_resource_set_int64 (resource, "nfo:duration", length);
+       tracker_resource_set_int64 (resource, "nfo:sampleRate", sample_rate);
+       tracker_resource_set_int64 (resource, "nfo:averageBitrate", avg_bps*1000);
 
        if (guess_dlna_profile (bitrate, sample_rate,
                                mpeg_ver, layer_ver, n_channels,
                                &dlna_profile, &dlna_mimetype)) {
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
-               tracker_sparql_builder_object_string (metadata, dlna_profile);
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
-               tracker_sparql_builder_object_string (metadata, dlna_mimetype);
+               tracker_resource_set_string (resource, "nmm:dlnaProfile", dlna_profile);
+               tracker_resource_set_string (resource, "nmm:dlnaMime", dlna_mimetype);
        }
 
        return TRUE;
@@ -1017,7 +1009,7 @@ mp3_parse (const gchar          *data,
            size_t                size,
            size_t                offset,
            const gchar          *uri,
-           TrackerSparqlBuilder *metadata,
+           TrackerResource      *resource,
            MP3Data              *filedata)
 {
        guint header;
@@ -1034,7 +1026,7 @@ mp3_parse (const gchar          *data,
 
                if ((header & sync_mask) == sync_mask) {
                        /* Found header sync */
-                       if (mp3_parse_header (data, size, pos, uri, metadata, filedata)) {
+                       if (mp3_parse_header (data, size, pos, uri, resource, filedata)) {
                                return TRUE;
                        }
                }
@@ -1246,7 +1238,7 @@ get_id3v24_tags (id3v24frame           frame,
                  size_t                csize,
                  id3tag               *info,
                  const gchar          *uri,
-                 TrackerSparqlBuilder *metadata,
+                 TrackerResource      *resource,
                  MP3Data              *filedata)
 {
        id3v2tag *tag = &filedata->id3v24;
@@ -1439,7 +1431,7 @@ get_id3v23_tags (id3v24frame           frame,
                  size_t                csize,
                  id3tag               *info,
                  const gchar          *uri,
-                 TrackerSparqlBuilder *metadata,
+                 TrackerResource      *resource,
                  MP3Data              *filedata)
 {
        id3v2tag *tag = &filedata->id3v23;
@@ -1624,7 +1616,7 @@ get_id3v20_tags (id3v2frame            frame,
                  size_t                csize,
                  id3tag               *info,
                  const gchar          *uri,
-                 TrackerSparqlBuilder *metadata,
+                 TrackerResource      *resource,
                  MP3Data              *filedata)
 {
        id3v2tag *tag = &filedata->id3v22;
@@ -1754,7 +1746,7 @@ parse_id3v24 (const gchar           *data,
               size_t                 size,
               id3tag                *info,
               const gchar           *uri,
-              TrackerSparqlBuilder  *metadata,
+              TrackerResource       *resource,
               MP3Data               *filedata,
               size_t                *offset_delta)
 {
@@ -1941,10 +1933,10 @@ parse_id3v24 (const gchar           *data,
                        gchar *body;
 
                        un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
-                       get_id3v24_tags (frame, body, unsync_size, info, uri, metadata, filedata);
+                       get_id3v24_tags (frame, body, unsync_size, info, uri, resource, filedata);
                        g_free (body);
                } else {
-                       get_id3v24_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
+                       get_id3v24_tags (frame, &data[pos], csize, info, uri, resource, filedata);
                }
 
                pos += csize;
@@ -1958,7 +1950,7 @@ parse_id3v23 (const gchar          *data,
               size_t                size,
               id3tag               *info,
               const gchar          *uri,
-              TrackerSparqlBuilder *metadata,
+              TrackerResource      *resource,
               MP3Data              *filedata,
               size_t               *offset_delta)
 {
@@ -2138,10 +2130,10 @@ parse_id3v23 (const gchar          *data,
                        gchar *body;
 
                        un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
-                       get_id3v23_tags (frame, body, unsync_size, info, uri, metadata, filedata);
+                       get_id3v23_tags (frame, body, unsync_size, info, uri, resource, filedata);
                        g_free (body);
                } else {
-                       get_id3v23_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
+                       get_id3v23_tags (frame, &data[pos], csize, info, uri, resource, filedata);
                }
 
                pos += csize;
@@ -2155,7 +2147,7 @@ parse_id3v20 (const gchar          *data,
               size_t                size,
               id3tag               *info,
               const gchar          *uri,
-              TrackerSparqlBuilder *metadata,
+              TrackerResource      *resource,
               MP3Data              *filedata,
               size_t               *offset_delta)
 {
@@ -2239,10 +2231,10 @@ parse_id3v20 (const gchar          *data,
                        gchar  *body;
 
                        un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
-                       get_id3v20_tags (frame, body, unsync_size, info, uri, metadata, filedata);
+                       get_id3v20_tags (frame, body, unsync_size, info, uri, resource, filedata);
                        g_free (body);
                } else {
-                       get_id3v20_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
+                       get_id3v20_tags (frame, &data[pos], csize, info, uri, resource, filedata);
                }
 
                pos += csize;
@@ -2256,7 +2248,7 @@ parse_id3v2 (const gchar          *data,
              size_t                size,
              id3tag               *info,
              const gchar          *uri,
-             TrackerSparqlBuilder *metadata,
+             TrackerResource      *resource,
              MP3Data              *filedata)
 {
        gboolean done = FALSE;
@@ -2264,9 +2256,9 @@ parse_id3v2 (const gchar          *data,
 
        do {
                size_t offset_delta = 0;
-               parse_id3v24 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
-               parse_id3v23 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
-               parse_id3v20 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
+               parse_id3v24 (data + offset, size - offset, info, uri, resource, filedata, &offset_delta);
+               parse_id3v23 (data + offset, size - offset, info, uri, resource, filedata, &offset_delta);
+               parse_id3v20 (data + offset, size - offset, info, uri, resource, filedata, &offset_delta);
 
                if (offset_delta == 0) {
                        done = TRUE;
@@ -2291,14 +2283,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        goffset  buffer_size;
        goffset audio_offset;
        MP3Data md = { 0 };
-       TrackerSparqlBuilder *metadata, *preupdate;
        GFile *file;
-       const gchar *graph;
        gboolean parsed;
-
-       graph = tracker_extract_info_get_graph (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
+       TrackerResource *main_resource;
 
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
@@ -2348,41 +2335,43 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        g_free (id3v1_buffer);
 
+       main_resource = tracker_resource_new (NULL);
+
        /* Get other embedded tags */
        uri = g_file_get_uri (file);
-       audio_offset = parse_id3v2 (buffer, buffer_size, &md.id3v1, uri, metadata, &md);
+       audio_offset = parse_id3v2 (buffer, buffer_size, &md.id3v1, uri, main_resource, &md);
 
        md.title = tracker_coalesce_strip (4, md.id3v24.title2,
                                           md.id3v23.title2,
                                           md.id3v22.title2,
                                           md.id3v1.title);
 
-       md.lyricist = tracker_coalesce_strip (4, md.id3v24.text,
-                                             md.id3v23.toly,
-                                             md.id3v23.text,
-                                             md.id3v22.text);
-
-       md.composer = tracker_coalesce_strip (3, md.id3v24.composer,
-                                             md.id3v23.composer,
-                                             md.id3v22.composer);
-
-       md.performer = tracker_coalesce_strip (7, md.id3v24.performer1,
-                                              md.id3v24.performer2,
-                                              md.id3v23.performer1,
-                                              md.id3v23.performer2,
-                                              md.id3v22.performer1,
-                                              md.id3v22.performer2,
-                                              md.id3v1.artist);
-
-       md.album_artist = tracker_coalesce_strip (4, md.id3v24.performer2,
-                                                 md.id3v23.performer2,
-                                                 md.id3v22.performer2,
-                                                 md.performer);
-
-       md.album = tracker_coalesce_strip (4, md.id3v24.album,
-                                          md.id3v23.album,
-                                          md.id3v22.album,
-                                          md.id3v1.album);
+       md.lyricist_name = tracker_coalesce_strip (4, md.id3v24.text,
+                                                  md.id3v23.toly,
+                                                  md.id3v23.text,
+                                                  md.id3v22.text);
+
+       md.composer_name = tracker_coalesce_strip (3, md.id3v24.composer,
+                                                  md.id3v23.composer,
+                                                  md.id3v22.composer);
+
+       md.performer_name = tracker_coalesce_strip (7, md.id3v24.performer1,
+                                                   md.id3v24.performer2,
+                                                   md.id3v23.performer1,
+                                                   md.id3v23.performer2,
+                                                   md.id3v22.performer1,
+                                                   md.id3v22.performer2,
+                                                   md.id3v1.artist);
+
+       md.album_artist_name = tracker_coalesce_strip (3, md.id3v24.performer2,
+                                                      md.id3v23.performer2,
+                                                      md.id3v22.performer2,
+                                                      md.performer);
+
+       md.album_name = tracker_coalesce_strip (4, md.id3v24.album,
+                                               md.id3v23.album,
+                                               md.id3v22.album,
+                                               md.id3v1.album);
 
        md.genre = tracker_coalesce_strip (7, md.id3v24.content_type,
                                           md.id3v24.title1,
@@ -2454,272 +2443,122 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                md.set_count = md.id3v22.set_count;
        }
 
-       if (md.performer) {
-               md.performer_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.performer);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, md.performer_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.performer);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+       if (md.performer_name) {
+               md.performer = tracker_extract_new_artist (md.performer_name);
        }
 
-       if (md.album_artist) {
-               md.album_artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.album_artist);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, md.album_artist_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.album_artist);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+       if (md.album_artist_name) {
+               md.album_artist = tracker_extract_new_artist (md.album_artist_name);
        }
 
-       if (md.composer) {
-               md.composer_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.composer);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, md.composer_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.composer);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+       if (md.composer_name) {
+               md.composer = tracker_extract_new_artist (md.composer_name);
        }
 
-       if (md.lyricist) {
-               md.lyricist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.lyricist);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, md.lyricist_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.lyricist);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+       if (md.lyricist_name) {
+               md.lyricist = tracker_extract_new_artist (md.lyricist_name);
        }
 
-       if (md.album) {
-               md.album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", md.album);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+       if (md.album_name) {
+               char *album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", md.album_name);
+               md.album = tracker_resource_new (album_uri);
 
-               tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum");
+               tracker_resource_set_uri (md.album, "rdf:type", "nmm:MusicAlbum");
                /* FIXME: nmm:albumTitle is now deprecated
                 * tracker_sparql_builder_predicate (preupdate, "nie:title");
                 */
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.album);
+               tracker_resource_set_string (md.album, "nmm:albumTitle", md.album_name);
 
-               if (md.album_artist_uri) {
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumArtist");
-                       tracker_sparql_builder_object_iri (preupdate, md.album_artist_uri);
+               if (md.album_artist) {
+                       tracker_resource_set_relation (md.album, "nmm:albumArtist", md.album_artist);
+                       g_object_unref (md.album_artist);
                }
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
                if (md.track_count > 0) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_int64 (preupdate, md.track_count);
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
+                       tracker_resource_set_int (md.album, "nmm:albumTrackCount", md.track_count);
                }
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
-       tracker_sparql_builder_object (metadata, "nfo:Audio");
+       tracker_resource_add_uri (main_resource, "rdf:type", "nmm:MusicPiece");
+       tracker_resource_add_uri (main_resource, "rdf:type", "nfo:Audio");
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          md.title,
-                                          uri,
-                                          NULL);
+       tracker_guarantee_resource_title_from_file (main_resource,
+                                                   "nie:title",
+                                                   md.title,
+                                                   uri,
+                                                   NULL);
 
-       if (md.lyricist_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:lyricist");
-               tracker_sparql_builder_object_iri (metadata, md.lyricist_uri);
-               g_free (md.lyricist_uri);
+       if (md.lyricist) {
+               tracker_resource_set_relation (main_resource, "nmm:lyricist", md.lyricist);
+               g_object_unref (md.lyricist);
        }
 
-       if (md.performer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:performer");
-               tracker_sparql_builder_object_iri (metadata, md.performer_uri);
-               g_free (md.performer_uri);
+       if (md.performer) {
+               tracker_resource_set_relation (main_resource, "nmm:performer", md.performer);
+               g_object_unref (md.performer);
        }
 
-       if (md.composer_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:composer");
-               tracker_sparql_builder_object_iri (metadata, md.composer_uri);
-               g_free (md.composer_uri);
+       if (md.composer) {
+               tracker_resource_set_relation (main_resource, "nmm:composer", md.composer);
+               g_object_unref (md.composer);
        }
 
-       if (md.album_uri) {
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbum");
-               tracker_sparql_builder_object_iri (metadata, md.album_uri);
+       if (md.album) {
+               tracker_resource_set_relation (main_resource, "nmm:musicAlbum", md.album);
        }
 
        if (md.recording_time) {
-               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-               tracker_sparql_builder_object_unvalidated (metadata, md.recording_time);
+               tracker_resource_set_string (main_resource, "nie:contentCreated", md.recording_time);
        }
 
        if (md.genre) {
-               tracker_sparql_builder_predicate (metadata, "nfo:genre");
-               tracker_sparql_builder_object_unvalidated (metadata, md.genre);
+               tracker_resource_set_string (main_resource, "nfo:genre", md.genre);
        }
 
        if (md.copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
+               tracker_resource_set_string (main_resource, "nie:copyright", md.copyright);
        }
 
        if (md.comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, md.comment);
+               tracker_resource_set_string (main_resource, "nie:comment", md.comment);
        }
 
        if (md.publisher) {
-               tracker_sparql_builder_predicate (metadata, "nco:publisher");
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, md.publisher);
-               tracker_sparql_builder_object_blank_close (metadata);
+               TrackerResource *publisher = tracker_extract_new_contact (md.publisher);
+               tracker_resource_set_relation (main_resource, "nco:publisher", publisher);
+               g_object_unref(publisher);
        }
 
        if (md.encoded_by) {
-               tracker_sparql_builder_predicate (metadata, "nfo:encodedBy");
-               tracker_sparql_builder_object_unvalidated (metadata, md.encoded_by);
+               tracker_resource_set_string (main_resource,  "nfo:encodedBy", md.encoded_by);
        }
 
        if (md.track_number > 0) {
-               tracker_sparql_builder_predicate (metadata, "nmm:trackNumber");
-               tracker_sparql_builder_object_int64 (metadata, md.track_number);
+               tracker_resource_set_int (main_resource, "nmm:trackNumber", md.track_number);
        }
 
        if (md.album) {
+               TrackerResource *album_disc;
                gchar *album_disc_uri;
 
                album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
-                                                                  md.album,
+                                                                  md.album_name,
                                                                   md.set_number > 0 ? md.set_number : 1);
 
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               album_disc = tracker_resource_new (album_disc_uri);
+               tracker_resource_set_uri (album_disc, "rdf:type", "nmm:MusicAlbumDisc");
+               tracker_resource_set_int (album_disc, "nmm:setNumber", md.set_number > 0 ? md.set_number : 1);
+               tracker_resource_set_relation (album_disc, "nmm:albumDiscAlbum", md.album);
 
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc");
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_int64 (preupdate, md.set_number > 0 ? md.set_number : 1);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_iri (preupdate, md.album_uri);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc");
-               tracker_sparql_builder_object_iri (metadata, album_disc_uri);
+               tracker_resource_set_relation (main_resource, "nmm:musicAlbumDisc", album_disc);
 
                g_free (album_disc_uri);
+               g_object_unref (album_disc);
+               g_object_unref (md.album);
        }
 
-       g_free (md.album_uri);
-       g_free (md.album_artist_uri);
-
        /* Get mp3 stream info */
-       parsed = mp3_parse (buffer, buffer_size, audio_offset, uri, metadata, &md);
+       parsed = mp3_parse (buffer, buffer_size, audio_offset, uri, main_resource, &md);
 
 #ifdef HAVE_LIBMEDIAART
        if (parsed && (md.performer || md.album)) {
@@ -2737,8 +2576,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                                            md.media_art_data,
                                                            md.media_art_size,
                                                            md.media_art_mime,
-                                                           md.performer,
-                                                           md.album,
+                                                           md.performer_name,
+                                                           md.album_name,
                                                            NULL,
                                                            &error);
                } else {
@@ -2746,8 +2585,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                                          MEDIA_ART_ALBUM,
                                                          MEDIA_ART_PROCESS_FLAGS_NONE,
                                                          file,
-                                                         md.performer,
-                                                         md.album,
+                                                         md.performer_name,
+                                                         md.album_name,
                                                          NULL,
                                                          &error);
                }
@@ -2772,6 +2611,11 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        munmap (buffer, buffer_size);
 #endif
 
+       if (main_resource) {
+               tracker_extract_info_set_resource (info, main_resource);
+               g_object_unref (main_resource);
+       }
+
        g_free (filename);
        g_free (uri);
 
diff --git a/src/tracker-extract/tracker-extract-msoffice-xml.c 
b/src/tracker-extract/tracker-extract-msoffice-xml.c
index 14a8345..1c6516c 100644
--- a/src/tracker-extract/tracker-extract-msoffice-xml.c
+++ b/src/tracker-extract/tracker-extract-msoffice-xml.c
@@ -76,7 +76,7 @@ typedef struct {
        MsOfficeXMLTagType tag_type;
 
        /* Metadata-parsing specific things */
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        guint has_title      : 1;
        guint has_subject    : 1;
        guint has_publisher  : 1;
@@ -436,8 +436,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_title = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nie:title", text);
                }
                break;
 
@@ -447,8 +446,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_subject = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nie:subject");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nie:subject", text);
                }
                break;
 
@@ -457,16 +455,12 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                        g_warning ("Avoiding additional publisher (%s) in MsOffice XML document '%s'",
                                   text, info->uri);
                } else {
-                       info->has_publisher = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nco:publisher");
+                       TrackerResource *publisher = tracker_extract_new_contact (text);
 
-                       tracker_sparql_builder_object_blank_open (info->metadata);
-                       tracker_sparql_builder_predicate (info->metadata, "a");
-                       tracker_sparql_builder_object (info->metadata, "nco:Contact");
+                       info->has_publisher = TRUE;
+                       tracker_resource_set_relation (info->metadata, "nco:publisher", publisher);
 
-                       tracker_sparql_builder_predicate (info->metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
-                       tracker_sparql_builder_object_blank_close (info->metadata);
+                       g_object_unref (publisher);
                }
                break;
 
@@ -476,8 +470,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_comment = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nie:comment");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nie:comment", text);
                }
                break;
 
@@ -491,8 +484,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                        date = tracker_date_guess (text);
                        if (date) {
                                info->has_content_created = TRUE;
-                               tracker_sparql_builder_predicate (info->metadata, "nie:contentCreated");
-                               tracker_sparql_builder_object_unvalidated (info->metadata, date);
+                               tracker_resource_set_string (info->metadata, "nie:contentCreated", date);
                                g_free (date);
                        } else {
                                g_warning ("Could not parse creation time (%s) from MsOffice XML document 
'%s'",
@@ -507,8 +499,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_generator = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nie:generator");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nie:generator", text);
                }
                break;
 
@@ -529,8 +520,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                        date = tracker_date_guess (text);
                        if (date) {
                                info->has_content_last_modified = TRUE;
-                               tracker_sparql_builder_predicate (info->metadata, "nie:contentLastModified");
-                               tracker_sparql_builder_object_unvalidated (info->metadata, date);
+                               tracker_resource_set_string (info->metadata, "nie:contentLastModified", date);
                                g_free (date);
                        } else {
                                g_warning ("Could not parse last modification time (%s) from MsOffice XML 
document '%s'",
@@ -545,8 +535,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_page_count = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nfo:pageCount");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nfo:pageCount", text);
                }
                break;
 
@@ -556,8 +545,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_char_count = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nfo:characterCount");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nfo:characterCount", text);
                }
                break;
 
@@ -567,8 +555,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_word_count = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nfo:wordCount");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nfo:wordCount", text);
                }
                break;
 
@@ -578,8 +565,7 @@ msoffice_xml_metadata_parse (GMarkupParseContext  *context,
                                   text, info->uri);
                } else {
                        info->has_line_count = TRUE;
-                       tracker_sparql_builder_predicate (info->metadata, "nfo:lineCount");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, text);
+                       tracker_resource_set_string (info->metadata, "nfo:lineCount", text);
                }
                break;
 
@@ -827,7 +813,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
 {
        MsOfficeXMLParserInfo info = { 0 };
        MsOfficeXMLFileType file_type;
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        TrackerConfig *config;
        GMarkupParseContext *context = NULL;
        GError *error = NULL;
@@ -838,7 +824,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
                maximum_size_error_quark = g_quark_from_static_string ("maximum_size_error");
        }
 
-       metadata = tracker_extract_info_get_metadata_builder (extract_info);
        file = tracker_extract_info_get_file (extract_info);
        uri = g_file_get_uri (file);
 
@@ -850,8 +835,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
 
        g_debug ("Extracting MsOffice XML format...");
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
 
        /* Setup Parser info */
        info.metadata = metadata;
@@ -894,8 +879,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
                info.content = NULL;
 
                if (content) {
-                       tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-                       tracker_sparql_builder_object_unvalidated (metadata, content);
+                       tracker_resource_set_string (metadata, "nie:plainTextContent", content);
                        g_free (content);
                }
        }
@@ -909,5 +893,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
        g_markup_parse_context_free (context);
        g_free (uri);
 
+       tracker_extract_info_set_resource (extract_info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-msoffice.c b/src/tracker-extract/tracker-extract-msoffice.c
index 5792215..976477c 100644
--- a/src/tracker-extract/tracker-extract-msoffice.c
+++ b/src/tracker-extract/tracker-extract-msoffice.c
@@ -125,7 +125,7 @@ typedef struct {
 } ExcelExtendedStringRecord;
 
 typedef struct {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        const gchar *uri;
 } MetadataInfo;
 
@@ -176,13 +176,12 @@ msoffice_string_process_octal_triplets (guchar *str)
 }
 
 static void
-metadata_add_gvalue (TrackerSparqlBuilder *metadata,
-                     const gchar          *uri,
-                     const gchar          *key,
-                     GValue const         *val,
-                     const gchar          *type,
-                     const gchar          *predicate,
-                     gboolean              is_date)
+metadata_add_gvalue (TrackerResource *metadata,
+                     const gchar     *key,
+                     GValue const    *val,
+                     const gchar     *type,
+                     const gchar     *predicate,
+                     gboolean         is_date)
 {
        gchar *s;
 
@@ -248,18 +247,15 @@ metadata_add_gvalue (TrackerSparqlBuilder *metadata,
                        msoffice_string_process_octal_triplets (str_val);
 
                        if (type && predicate) {
-                               tracker_sparql_builder_predicate (metadata, key);
+                               TrackerResource *child = tracker_resource_new (NULL);
+                               tracker_resource_set_uri (child, "rdf:type", type);
+                               tracker_resource_set_string (child, predicate, str_val);
 
-                               tracker_sparql_builder_object_blank_open (metadata);
-                               tracker_sparql_builder_predicate (metadata, "a");
-                               tracker_sparql_builder_object (metadata, type);
+                               tracker_resource_add_relation (metadata, key, child);
 
-                               tracker_sparql_builder_predicate (metadata, predicate);
-                               tracker_sparql_builder_object_unvalidated (metadata, str_val);
-                               tracker_sparql_builder_object_blank_close (metadata);
+                               g_object_unref (child);
                        } else {
-                               tracker_sparql_builder_predicate (metadata, key);
-                               tracker_sparql_builder_object_unvalidated (metadata, str_val);
+                               tracker_resource_set_string (metadata, key, str_val);
                        }
 
                        g_free (str_val);
@@ -280,11 +276,11 @@ summary_metadata_cb (gpointer key,
        val = gsf_doc_prop_get_val (value);
 
        if (g_strcmp0 (key, "dc:title") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nie:title", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nie:title", val, NULL, NULL, FALSE);
        } else if (g_strcmp0 (key, "dc:subject") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nie:subject", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nie:subject", val, NULL, NULL, FALSE);
        } else if (g_strcmp0 (key, "dc:creator") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nco:creator", val, "nco:Contact", 
"nco:fullname", FALSE);
+               metadata_add_gvalue (info->metadata, "nco:creator", val, "nco:Contact", "nco:fullname", 
FALSE);
        } else if (g_strcmp0 (key, "dc:keywords") == 0) {
                gchar *keywords, *str = g_strdup_value_contents (val);
                gchar *lasts, *keyw;
@@ -306,21 +302,20 @@ summary_metadata_cb (gpointer key,
 
                for (keyw = strtok_r (keywords, ",; ", &lasts); keyw;
                     keyw = strtok_r (NULL, ",; ", &lasts)) {
-                       tracker_sparql_builder_predicate (info->metadata, "nie:keyword");
-                       tracker_sparql_builder_object_unvalidated (info->metadata, keyw);
+                       tracker_resource_add_string (info->metadata, "nie:keyword", keyw);
                }
 
                g_free (str);
        } else if (g_strcmp0 (key, "dc:description") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nie:comment", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nie:comment", val, NULL, NULL, FALSE);
        } else if (g_strcmp0 (key, "gsf:page-count") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nfo:pageCount", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nfo:pageCount", val, NULL, NULL, FALSE);
        } else if (g_strcmp0 (key, "gsf:word-count") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nfo:wordCount", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nfo:wordCount", val, NULL, NULL, FALSE);
        } else if (g_strcmp0 (key, "meta:creation-date") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nie:contentCreated", val, NULL, NULL, TRUE);
+               metadata_add_gvalue (info->metadata, "nie:contentCreated", val, NULL, NULL, TRUE);
        } else if (g_strcmp0 (key, "meta:generator") == 0) {
-               metadata_add_gvalue (info->metadata, info->uri, "nie:generator", val, NULL, NULL, FALSE);
+               metadata_add_gvalue (info->metadata, "nie:generator", val, NULL, NULL, FALSE);
        }
 }
 
@@ -333,7 +328,6 @@ document_metadata_cb (gpointer key,
                MetadataInfo *info = user_data;
 
                metadata_add_gvalue (info->metadata,
-                                    info->uri,
                                     "nie:license",
                                     gsf_doc_prop_get_val (value),
                                     NULL,
@@ -1548,15 +1542,12 @@ extract_excel_content (GsfInfile *infile,
  * @param uri uri of the file
  */
 static gboolean
-extract_summary (TrackerSparqlBuilder *metadata,
-                 GsfInfile            *infile,
-                 const gchar          *uri)
+extract_summary (TrackerResource *metadata,
+                 GsfInfile       *infile,
+                 const gchar     *uri)
 {
        GsfInput *stream;
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
-
        stream = gsf_infile_child_by_name (infile, "\05SummaryInformation");
 
        if (stream) {
@@ -1632,7 +1623,7 @@ extract_summary (TrackerSparqlBuilder *metadata,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        TrackerConfig *config;
        GsfInfile *infile = NULL;
        gchar *content = NULL, *uri;
@@ -1645,7 +1636,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        gsf_init ();
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
        mime_used = tracker_extract_info_get_mimetype (info);
 
        file = tracker_extract_info_get_file (info);
@@ -1673,6 +1663,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
+       metadata = tracker_resource_new (NULL);
+
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
+
        /* Extracting summary */
        extract_summary (metadata, infile, uri);
 
@@ -1685,14 +1679,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                content = extract_msword_content (infile, max_bytes, &is_encrypted);
        } else if (g_ascii_strcasecmp (mime_used, "application/vnd.ms-powerpoint") == 0) {
                /* PowerPoint file */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nfo:Presentation");
+               tracker_resource_add_uri (metadata, "rdf:type", "nfo:Presentation");
 
                content = extract_powerpoint_content (infile, max_bytes, &is_encrypted);
        } else if (g_ascii_strcasecmp (mime_used, "application/vnd.ms-excel") == 0) {
                /* Excel File */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nfo:Spreadsheet");
+               tracker_resource_add_uri(metadata, "rdf:type", "nfo:Spreadsheet");
 
                content = extract_excel_content (infile, max_bytes, &is_encrypted);
        } else {
@@ -1700,14 +1692,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (content) {
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, content);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", content);
                g_free (content);
        }
 
        if (is_encrypted) {
-               tracker_sparql_builder_predicate (metadata, "nfo:isContentEncrypted");
-               tracker_sparql_builder_object_boolean (metadata, TRUE);
+               tracker_resource_set_boolean (metadata, "nfo:isContentEncrypted", TRUE);
        }
 
        g_object_unref (infile);
@@ -1717,5 +1707,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                tracker_file_close (mfile, FALSE);
        }
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-oasis.c b/src/tracker-extract/tracker-extract-oasis.c
index 5e4bea0..704dd2a 100644
--- a/src/tracker-extract/tracker-extract-oasis.c
+++ b/src/tracker-extract/tracker-extract-oasis.c
@@ -55,7 +55,7 @@ typedef enum {
 } ODTFileType;
 
 typedef struct {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        ODTTagType current;
        const gchar *uri;
        guint has_title           : 1;
@@ -110,13 +110,13 @@ static void xml_text_handler_content           (GMarkupParseContext   *context,
 static void extract_oasis_content              (const gchar           *uri,
                                                 gulong                 total_bytes,
                                                 ODTFileType            file_type,
-                                                TrackerSparqlBuilder  *metadata);
+                                                TrackerResource       *metadata);
 
 static void
-extract_oasis_content (const gchar          *uri,
-                       gulong                total_bytes,
-                       ODTFileType           file_type,
-                       TrackerSparqlBuilder *metadata)
+extract_oasis_content (const gchar     *uri,
+                       gulong           total_bytes,
+                       ODTFileType      file_type,
+                       TrackerResource *metadata)
 {
        gchar *content = NULL;
        ODTContentParseInfo info;
@@ -150,8 +150,7 @@ extract_oasis_content (const gchar          *uri,
 
        if (!error || g_error_matches (error, maximum_size_error_quark, 0)) {
                content = g_string_free (info.content, FALSE);
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, content);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", content);
        } else {
                g_warning ("Got error parsing XML file: %s\n", error->message);
                g_string_free (info.content, TRUE);
@@ -168,7 +167,7 @@ extract_oasis_content (const gchar          *uri,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        TrackerConfig *config;
        ODTMetadataParseInfo info = { 0 };
        ODTFileType file_type;
@@ -188,7 +187,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
                maximum_size_error_quark = g_quark_from_static_string ("maximum_size_error");
        }
 
-       metadata = tracker_extract_info_get_metadata_builder (extract_info);
+       metadata = tracker_resource_new (NULL);
        mime_used = tracker_extract_info_get_mimetype (extract_info);
 
        file = tracker_extract_info_get_file (extract_info);
@@ -201,8 +200,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
 
        /* First, parse metadata */
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
 
        /* Create parse info */
        info.metadata = metadata;
@@ -238,6 +236,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *extract_info)
 
        g_free (uri);
 
+       tracker_extract_info_set_resource (extract_info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
 
@@ -262,7 +263,7 @@ xml_start_element_handler_metadata (GMarkupParseContext  *context,
        } else if (g_ascii_strcasecmp (element_name, "dc:description") == 0) {
                data->current = ODT_TAG_TYPE_COMMENTS;
        } else if (g_ascii_strcasecmp (element_name, "meta:document-statistic") == 0) {
-               TrackerSparqlBuilder *metadata;
+               TrackerResource *metadata;
                const gchar **a, **v;
 
                metadata = data->metadata;
@@ -274,8 +275,7 @@ xml_start_element_handler_metadata (GMarkupParseContext  *context,
                                                   *v, data->uri);
                                } else {
                                        data->has_word_count = TRUE;
-                                       tracker_sparql_builder_predicate (metadata, "nfo:wordCount");
-                                       tracker_sparql_builder_object_unvalidated (metadata, *v);
+                                       tracker_resource_set_string (metadata, "nfo:wordCount", *v);
                                }
                        } else if (g_ascii_strcasecmp (*a, "meta:page-count") == 0) {
                                if (data->has_page_count) {
@@ -283,8 +283,7 @@ xml_start_element_handler_metadata (GMarkupParseContext  *context,
                                                   *v, data->uri);
                                } else {
                                        data->has_page_count = TRUE;
-                                       tracker_sparql_builder_predicate (metadata, "nfo:pageCount");
-                                       tracker_sparql_builder_object_unvalidated (metadata, *v);
+                                       tracker_resource_set_string (metadata, "nfo:pageCount", *v);
                                }
                        }
                }
@@ -316,7 +315,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                            GError              **error)
 {
        ODTMetadataParseInfo *data;
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        gchar *date;
 
        data = user_data;
@@ -334,8 +333,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                                   text, data->uri);
                } else {
                        data->has_title = TRUE;
-                       tracker_sparql_builder_predicate (metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (metadata, text);
+                       tracker_resource_set_string (metadata, "nie:title", text);
                }
                break;
 
@@ -345,8 +343,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                                   text, data->uri);
                } else {
                        data->has_subject = TRUE;
-                       tracker_sparql_builder_predicate (metadata, "nie:subject");
-                       tracker_sparql_builder_object_unvalidated (metadata, text);
+                       tracker_resource_set_string (metadata, "nie:subject", text);
                }
                break;
 
@@ -355,16 +352,12 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                        g_warning ("Avoiding additional publisher (%s) in OASIS document '%s'",
                                   text, data->uri);
                } else {
-                       data->has_publisher = TRUE;
-                       tracker_sparql_builder_predicate (metadata, "nco:publisher");
+                       TrackerResource *publisher = tracker_extract_new_contact (text);
 
-                       tracker_sparql_builder_object_blank_open (metadata);
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nco:Contact");
+                       data->has_publisher = TRUE;
+                       tracker_resource_set_relation (metadata, "nco:publisher", publisher);
 
-                       tracker_sparql_builder_predicate (metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (metadata, text);
-                       tracker_sparql_builder_object_blank_close (metadata);
+                       g_object_unref (publisher);
                }
                break;
 
@@ -377,8 +370,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                for (keyw = strtok_r (keywords, ",; ", &lasts);
                     keyw;
                     keyw = strtok_r (NULL, ",; ", &lasts)) {
-                       tracker_sparql_builder_predicate (metadata, "nie:keyword");
-                       tracker_sparql_builder_object_unvalidated (metadata, keyw);
+                       tracker_resource_add_string (metadata, "nie:keyword", keyw);
                }
 
                g_free (keywords);
@@ -392,8 +384,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                                   text, data->uri);
                } else {
                        data->has_comment = TRUE;
-                       tracker_sparql_builder_predicate (metadata, "nie:comment");
-                       tracker_sparql_builder_object_unvalidated (metadata, text);
+                       tracker_resource_set_string (metadata, "nie:comment", text);
                }
                break;
 
@@ -405,8 +396,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                        date = tracker_date_guess (text);
                        if (date) {
                                data->has_content_created = TRUE;
-                               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-                               tracker_sparql_builder_object_unvalidated (metadata, date);
+                               tracker_resource_set_string (metadata, "nie:contentCreated", date);
                                g_free (date);
                        } else {
                                g_warning ("Could not parse creation time (%s) in OASIS document '%s'",
@@ -421,8 +411,7 @@ xml_text_handler_metadata (GMarkupParseContext  *context,
                                   text, data->uri);
                } else {
                        data->has_generator = TRUE;
-                       tracker_sparql_builder_predicate (metadata, "nie:generator");
-                       tracker_sparql_builder_object_unvalidated (metadata, text);
+                       tracker_resource_set_string (metadata, "nie:generator", text);
                }
                break;
 
diff --git a/src/tracker-extract/tracker-extract-pdf.c b/src/tracker-extract/tracker-extract-pdf.c
index 6402ddd..b6b4274 100644
--- a/src/tracker-extract/tracker-extract-pdf.c
+++ b/src/tracker-extract/tracker-extract-pdf.c
@@ -169,8 +169,8 @@ read_toc (PopplerIndexIter  *index,
 }
 
 static void
-read_outline (PopplerDocument      *document,
-              TrackerSparqlBuilder *metadata)
+read_outline (PopplerDocument *document,
+              TrackerResource *metadata)
 {
        PopplerIndexIter *index;
        GString *toc = NULL;
@@ -185,8 +185,7 @@ read_outline (PopplerDocument      *document,
 
        if (toc) {
                if (toc->len > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:tableOfContents");
-                       tracker_sparql_builder_object_unvalidated (metadata, toc->str);
+                       tracker_resource_set_string (metadata, "nfo:tableOfContents", toc->str);
                }
 
                g_string_free (toc, TRUE);
@@ -256,33 +255,26 @@ extract_content_text (PopplerDocument *document,
 }
 
 static void
-write_pdf_data (PDFData               data,
-                TrackerSparqlBuilder *metadata,
-                GPtrArray            *keywords)
+write_pdf_data (PDFData          data,
+                TrackerResource *metadata,
+                GPtrArray       *keywords)
 {
        if (!tracker_is_empty_string (data.title)) {
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_unvalidated (metadata, data.title);
+               tracker_resource_set_string (metadata, "nie:title", data.title);
        }
 
        if (!tracker_is_empty_string (data.subject)) {
-               tracker_sparql_builder_predicate (metadata, "nie:subject");
-               tracker_sparql_builder_object_unvalidated (metadata, data.subject);
+               tracker_resource_set_string (metadata, "nie:subject", data.subject);
        }
 
        if (!tracker_is_empty_string (data.author)) {
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, data.author);
-               tracker_sparql_builder_object_blank_close (metadata);
+               TrackerResource *author = tracker_extract_new_contact (data.author);
+               tracker_resource_set_relation (metadata, "nco:creator", author);
+               g_object_unref (author);
        }
 
        if (!tracker_is_empty_string (data.date)) {
-               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-               tracker_sparql_builder_object_unvalidated (metadata, data.date);
+               tracker_resource_set_string (metadata, "nie:contentCreated", data.date);
        }
 
        if (!tracker_is_empty_string (data.keywords)) {
@@ -296,9 +288,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        TrackerConfig *config;
        GTime creation_date;
        GError *error = NULL;
-       TrackerSparqlBuilder *metadata, *preupdate;
-       const gchar *graph;
-       const gchar *urn;
+       TrackerResource *metadata;
        TrackerXmpData *xd = NULL;
        PDFData pd = { 0 }; /* actual data */
        PDFData md = { 0 }; /* for merging */
@@ -315,11 +305,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        gsize len;
        struct stat st;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-       urn = tracker_extract_info_get_urn (info);
-
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
 
@@ -362,14 +347,16 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        uri = g_file_get_uri (file);
 
        document = poppler_document_new_from_data (contents, len, NULL, &error);
-       
+
        if (error) {
                if (error->code == POPPLER_ERROR_ENCRYPTED) {
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+                       metadata = tracker_resource_new (NULL);
+
+                       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
+                       tracker_resource_set_boolean (metadata, "nfo:isContentEncrypted", TRUE);
 
-                       tracker_sparql_builder_predicate (metadata, "nfo:isContentEncrypted");
-                       tracker_sparql_builder_object_boolean (metadata, TRUE);
+                       tracker_extract_info_set_resource (info, metadata);
+                       g_object_unref (metadata);
 
                        g_error_free (error);
                        g_free (uri);
@@ -398,8 +385,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
 
        g_object_get (document,
                      "title", &pd.title,
@@ -435,243 +422,131 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                }
 
                if (xd->publisher) {
-                       tracker_sparql_builder_predicate (metadata, "nco:publisher");
-                       tracker_sparql_builder_object_blank_open (metadata);
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nco:Contact");
-                       tracker_sparql_builder_predicate (metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->publisher);
-                       tracker_sparql_builder_object_blank_close (metadata);
+                       TrackerResource *publisher = tracker_extract_new_contact (xd->publisher);
+                       tracker_resource_set_relation (metadata, "nco:publisher", publisher);
+                       g_object_unref (publisher);
                }
 
                if (xd->type) {
-                       tracker_sparql_builder_predicate (metadata, "dc:type");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->type);
+                       tracker_resource_set_string (metadata, "dc:type", xd->type);
                }
 
                if (xd->format) {
-                       tracker_sparql_builder_predicate (metadata, "dc:format");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->format);
+                       tracker_resource_set_string (metadata, "dc:format", xd->format);
                }
 
                if (xd->identifier) {
-                       tracker_sparql_builder_predicate (metadata, "dc:identifier");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
+                       tracker_resource_set_string (metadata, "dc:identifier", xd->identifier);
                }
 
                if (xd->source) {
-                       tracker_sparql_builder_predicate (metadata, "dc:source");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->source);
+                       tracker_resource_set_string (metadata, "dc:source", xd->source);
                }
 
                if (xd->language) {
-                       tracker_sparql_builder_predicate (metadata, "dc:language");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->language);
+                       tracker_resource_set_string (metadata, "dc:language", xd->language);
                }
 
                if (xd->relation) {
-                       tracker_sparql_builder_predicate (metadata, "dc:relation");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
+                       tracker_resource_set_string (metadata, "dc:relation", xd->relation);
                }
 
                if (xd->coverage) {
-                       tracker_sparql_builder_predicate (metadata, "dc:coverage");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
+                       tracker_resource_set_string (metadata, "dc:coverage", xd->coverage);
                }
 
                if (xd->license) {
-                       tracker_sparql_builder_predicate (metadata, "nie:license");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->license);
+                       tracker_resource_set_string (metadata, "nie:license", xd->license);
                }
 
                if (xd->make || xd->model) {
-                       gchar *equip_uri;
-
-                       equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                                     xd->make ? xd->make : "",
-                                                                     xd->model ? xd->model : "");
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nfo:Equipment");
-
-                       if (xd->make) {
-                               tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->make);
-                       }
-
-                       if (xd->model) {
-                               tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                               tracker_sparql_builder_object_unvalidated (preupdate, xd->model);
-                       }
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-
-                       tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-                       tracker_sparql_builder_object_iri (metadata, equip_uri);
-                       g_free (equip_uri);
+                       TrackerResource *equipment = tracker_extract_new_equipment (xd->make, xd->model);
+                       tracker_resource_set_relation (metadata, "nfo:equipment", equipment);
+                       g_object_unref (equipment);
                }
 
                if (xd->orientation) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-                       tracker_sparql_builder_object (metadata, xd->orientation);
+                       tracker_resource_set_string (metadata, "nfo:orientation", xd->orientation);
                }
 
                if (xd->rights) {
-                       tracker_sparql_builder_predicate (metadata, "nie:copyright");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->rights);
+                       tracker_resource_set_string (metadata, "nie:copyright", xd->rights);
                }
 
                if (xd->white_balance) {
-                       tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-                       tracker_sparql_builder_object (metadata, xd->white_balance);
+                       tracker_resource_set_string (metadata, "nmm:whiteBalance", xd->white_balance);
                }
 
                if (xd->fnumber) {
                        gdouble value;
 
                        value = g_strtod (xd->fnumber, NULL);
-                       tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-                       tracker_sparql_builder_object_double (metadata, value);
+                       tracker_resource_set_double (metadata, "nmm:fnumber", value);
                }
 
                if (xd->flash) {
-                       tracker_sparql_builder_predicate (metadata, "nmm:flash");
-                       tracker_sparql_builder_object (metadata, xd->flash);
+                       tracker_resource_set_string (metadata, "nmm:flash", xd->flash);
                }
 
                if (xd->focal_length) {
                        gdouble value;
 
                        value = g_strtod (xd->focal_length, NULL);
-                       tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-                       tracker_sparql_builder_object_double (metadata, value);
+                       tracker_resource_set_double (metadata, "nmm:focalLength", value);
                }
 
                /* Question: Shouldn't xd->Artist be merged with md.author instead? */
 
                if (xd->artist || xd->contributor) {
-                       const gchar *artist;
+                       TrackerResource *artist;
+                       const gchar *artist_name;
+
+                       artist_name = tracker_coalesce_strip (2, xd->artist, xd->contributor);
+
+                       artist = tracker_extract_new_contact (artist_name);
+
+                       tracker_resource_set_relation (metadata, "nco:contributor", artist);
 
-                       artist = tracker_coalesce_strip (2, xd->artist, xd->contributor);
-                       tracker_sparql_builder_predicate (metadata, "nco:contributor");
-                       tracker_sparql_builder_object_blank_open (metadata);
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nco:Contact");
-                       tracker_sparql_builder_predicate (metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (metadata, artist);
-                       tracker_sparql_builder_object_blank_close (metadata);
+                       g_object_unref (artist);
                }
 
                if (xd->exposure_time) {
                        gdouble value;
 
                        value = g_strtod (xd->exposure_time, NULL);
-                       tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-                       tracker_sparql_builder_object_double (metadata, value);
+                       tracker_resource_set_double (metadata, "nmm:exposureTime", value);
                }
 
                if (xd->iso_speed_ratings) {
                        gdouble value;
 
                        value = g_strtod (xd->iso_speed_ratings, NULL);
-                       tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-                       tracker_sparql_builder_object_double (metadata, value);
+                       tracker_resource_set_double (metadata, "nmm:isoSpeed", value);
                }
 
                if (xd->description) {
-                       tracker_sparql_builder_predicate (metadata, "nie:description");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->description);
+                       tracker_resource_set_string (metadata, "nie:description", xd->description);
                }
 
                if (xd->metering_mode) {
-                       tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-                       tracker_sparql_builder_object (metadata, xd->metering_mode);
+                       tracker_resource_set_string (metadata, "nmm:meteringMode", xd->metering_mode);
                }
 
                if (xd->address || xd->state || xd->country || xd->city ||
                    xd->gps_altitude || xd->gps_latitude || xd-> gps_longitude) {
 
-                       tracker_sparql_builder_predicate (metadata, "slo:location");
-
-                       tracker_sparql_builder_object_blank_open (metadata); /* GeoLocation */
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "slo:GeoLocation");
-                       
-                       if (xd->address || xd->state || xd->country || xd->city)  {
-                               gchar *addruri;
-                               addruri = tracker_sparql_get_uuid_urn ();
-
-                               tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                               tracker_sparql_builder_object_iri (metadata, addruri);                  
-
-                               tracker_sparql_builder_insert_open (preupdate, NULL);
-                               if (graph) {
-                                       tracker_sparql_builder_graph_open (preupdate, graph);
-                               }
-
-                               tracker_sparql_builder_subject_iri (preupdate, addruri);
+                       TrackerResource *location = tracker_extract_new_location (xd->address,
+                               xd->state, xd->city, xd->country, xd->gps_altitude,
+                               xd->gps_latitude, xd->gps_longitude);
 
-                               g_free (addruri);
+                       tracker_resource_set_relation (metadata, "slo:location", location);
 
-                               tracker_sparql_builder_predicate (preupdate, "a");
-                               tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
-
-                               if (xd->address) {
-                                       tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                                       tracker_sparql_builder_object_unvalidated (preupdate, xd->address);
-                               }
-
-                               if (xd->state) {
-                                       tracker_sparql_builder_predicate (preupdate, "nco:region");
-                                       tracker_sparql_builder_object_unvalidated (preupdate, xd->state);
-                               }
-
-                               if (xd->city) {
-                                       tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                                       tracker_sparql_builder_object_unvalidated (preupdate, xd->city);
-                               }
-
-                               if (xd->country) {
-                                       tracker_sparql_builder_predicate (preupdate, "nco:country");
-                                       tracker_sparql_builder_object_unvalidated (preupdate, xd->country);
-                               }
-
-                               if (graph) {
-                                       tracker_sparql_builder_graph_close (preupdate);
-                               }
-                               tracker_sparql_builder_insert_close (preupdate);
-                       }
-
-                       if (xd->gps_altitude) {
-                               tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                               tracker_sparql_builder_object_unvalidated (metadata, xd->gps_altitude);
-                       }
-
-                       if (xd->gps_latitude) {
-                               tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                               tracker_sparql_builder_object_unvalidated (metadata, xd->gps_latitude);
-                       }
-
-                       if (xd->gps_longitude) {
-                               tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                               tracker_sparql_builder_object_unvalidated (metadata, xd->gps_longitude);
-                       }
-
-                       tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+                       g_object_unref (location);
                }
 
-                if (xd->regions) {
-                       tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
-                }
+               if (xd->regions) {
+                       tracker_xmp_apply_regions_to_resource (metadata, xd);
+               }
 
                tracker_xmp_free (xd);
        } else {
@@ -682,57 +557,26 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *escaped, *subject;
+               TrackerResource *tag;
                const gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               subject = g_strdup_printf ("_:tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject (preupdate, subject);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_append (preupdate,
-                                              "WHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
-
-               /* associate file with tag */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject_iri (preupdate, urn);
-               tracker_sparql_builder_predicate (preupdate, "nao:hasTag");
-               tracker_sparql_builder_object (preupdate, "?tag");
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject (preupdate, "?tag");
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_where_close (preupdate);
-
-               g_free (subject);
-               g_free (escaped);
+               tag = tracker_extract_new_tag (p);
+
+               tracker_resource_add_relation (metadata, "nao:hasTag", tag);
+
+               g_object_unref (tag);
        }
        g_ptr_array_free (keywords, TRUE);
 
-       tracker_sparql_builder_predicate (metadata, "nfo:pageCount");
-       tracker_sparql_builder_object_int64 (metadata, poppler_document_get_n_pages (document));
+       tracker_resource_set_int64 (metadata, "nfo:pageCount", poppler_document_get_n_pages(document));
 
        config = tracker_main_get_config ();
        n_bytes = tracker_config_get_max_bytes (config);
        content = extract_content_text (document, n_bytes);
 
        if (content) {
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, content);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", content);
                g_free (content);
        }
 
@@ -755,5 +599,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        close (fd);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-playlist.c b/src/tracker-extract/tracker-extract-playlist.c
index 0d16c0d..943b1ce 100644
--- a/src/tracker-extract/tracker-extract-playlist.c
+++ b/src/tracker-extract/tracker-extract-playlist.c
@@ -46,7 +46,7 @@ typedef struct {
        guint32 track_counter;
        gint64 total_time;
        gchar *title;
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
 } PlaylistMetadata;
 
 static void
@@ -69,6 +69,7 @@ entry_parsed (TotemPlParser *parser,
               GHashTable    *to_metadata,
               gpointer       user_data)
 {
+       TrackerResource *entry;
        PlaylistMetadata *data;
 
        data = (PlaylistMetadata *) user_data;
@@ -80,22 +81,19 @@ entry_parsed (TotemPlParser *parser,
                return;
        }
 
+       entry = tracker_resource_new (NULL);
+       tracker_resource_set_uri (entry, "rdf:type", "nfo:MediaFileListEntry");
+       tracker_resource_set_string (entry, "nfo:entryUrl", to_uri);
+       tracker_resource_set_int (entry, "nfo:listPosition", data->track_counter);
+
        if (data->track_counter == 1) {
-               /* first track, predicate needed */
-               tracker_sparql_builder_predicate (data->metadata, "nfo:hasMediaFileListEntry");
+               /* This causes all existing relations to be deleted, when we serialize
+                * to SPARQL. */
+               tracker_resource_set_relation (data->metadata, "nfo:hasMediaFileListEntry", entry);
+       } else {
+               tracker_resource_add_relation (data->metadata, "nfo:hasMediaFileListEntry", entry);
        }
-
-       tracker_sparql_builder_object_blank_open (data->metadata);
-       tracker_sparql_builder_predicate (data->metadata, "a");
-       tracker_sparql_builder_object (data->metadata, "nfo:MediaFileListEntry");
-
-       tracker_sparql_builder_predicate (data->metadata, "nfo:entryUrl");
-       tracker_sparql_builder_object_unvalidated (data->metadata, to_uri);
-
-       tracker_sparql_builder_predicate (data->metadata, "nfo:listPosition");
-       tracker_sparql_builder_object_int64 (data->metadata, (gint64) data->track_counter);
-
-       tracker_sparql_builder_object_blank_close (data->metadata);
+       g_object_unref (entry);
 
        if (to_metadata) {
                gchar *duration;
@@ -120,7 +118,7 @@ G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
        TotemPlParser *pl;
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        PlaylistMetadata data;
        GFile *file;
        gchar *uri;
@@ -128,41 +126,37 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        pl = totem_pl_parser_new ();
        file = tracker_extract_info_get_file (info);
        uri = g_file_get_uri (file);
-       metadata = tracker_extract_info_get_metadata_builder (info);
+
+       metadata = data.metadata = tracker_resource_new (NULL);
 
        data.track_counter = PLAYLIST_DEFAULT_NO_TRACKS;
        data.total_time =  PLAYLIST_DEFAULT_DURATION;
        data.title = NULL;
-       data.metadata = metadata;
 
        g_object_set (pl, "recurse", FALSE, "disable-unsafe", TRUE, NULL);
 
        g_signal_connect (G_OBJECT (pl), "playlist-started", G_CALLBACK (playlist_started), &data);
        g_signal_connect (G_OBJECT (pl), "entry-parsed", G_CALLBACK (entry_parsed), &data);
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nmm:Playlist");
-       tracker_sparql_builder_object (metadata, "nfo:MediaList");
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:Playlist");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:MediaList");
 
        if (totem_pl_parser_parse (pl, uri, FALSE) == TOTEM_PL_PARSER_RESULT_SUCCESS) {
                if (data.title != NULL) {
                        g_message ("Playlist title:'%s'", data.title);
-                       tracker_sparql_builder_predicate (metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (metadata, data.title);
+                       tracker_resource_set_string (metadata, "nie:title", data.title);
                        g_free (data.title);
                } else {
                        g_message ("Playlist has no title, attempting to get one from filename");
-                       tracker_guarantee_title_from_file (metadata, "nie:title", NULL, uri, NULL);
+                       tracker_guarantee_resource_title_from_file (metadata, "nie:title", NULL, uri, NULL);
                }
 
                if (data.total_time > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:listDuration");
-                       tracker_sparql_builder_object_int64 (metadata, data.total_time);
+                       tracker_resource_set_int64 (metadata, "nfo:listDuration", data.total_time);
                }
 
                if (data.track_counter > 0) {
-                       tracker_sparql_builder_predicate (metadata, "nfo:entryCounter");
-                       tracker_sparql_builder_object_int64 (metadata, data.track_counter);
+                       tracker_resource_set_int64 (metadata, "nfo:entryCounter", data.track_counter);
                }
        } else {
                g_warning ("Playlist could not be parsed, no error given");
@@ -171,5 +165,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        g_object_unref (pl);
        g_free (uri);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-png.c b/src/tracker-extract/tracker-extract-png.c
index a7aa705..2bf13cb 100644
--- a/src/tracker-extract/tracker-extract-png.c
+++ b/src/tracker-extract/tracker-extract-png.c
@@ -183,14 +183,11 @@ raw_profile_new (const gchar *input,
 #endif /* defined(PNG_iTXt_SUPPORTED) && (defined(HAVE_EXEMPI) || defined(HAVE_LIBEXIF)) */
 
 static void
-read_metadata (TrackerSparqlBuilder *preupdate,
-               TrackerSparqlBuilder *metadata,
+read_metadata (TrackerResource      *metadata,
                png_structp           png_ptr,
                png_infop             info_ptr,
                png_infop             end_ptr,
-               const gchar          *uri,
-               const gchar          *graph,
-               const gchar          *urn)
+               const gchar          *uri)
 {
        MergeData md = { 0 };
        PngData pd = { 0 };
@@ -364,159 +361,87 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        keywords = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
 
        if (md.comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, md.comment);
+               tracker_resource_set_string (metadata, "nie:comment", md.comment);
        }
 
        if (md.license) {
-               tracker_sparql_builder_predicate (metadata, "nie:license");
-               tracker_sparql_builder_object_unvalidated (metadata, md.license);
+               tracker_resource_set_string (metadata, "nie:license", md.license);
        }
 
        /* TODO: add ontology and store this ed->software */
 
        if (md.creator) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
+               TrackerResource *creator = tracker_extract_new_contact (md.creator);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               tracker_resource_set_relation (metadata, "nco:creator", creator);
 
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (creator);
        }
 
-       tracker_guarantee_date_from_file_mtime (metadata,
-                                               "nie:contentCreated",
-                                               md.date,
-                                               uri);
+       tracker_guarantee_resource_date_from_file_mtime (metadata,
+                                                        "nie:contentCreated",
+                                                        md.date,
+                                                        uri);
 
        if (md.description) {
-               tracker_sparql_builder_predicate (metadata, "nie:description");
-               tracker_sparql_builder_object_unvalidated (metadata, md.description);
+               tracker_resource_set_string (metadata, "nie:description", md.description);
        }
 
        if (md.copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
+               tracker_resource_set_string (metadata, "nie:copyright", md.copyright);
        }
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          md.title,
-                                          uri,
-                                          NULL);
+       tracker_guarantee_resource_title_from_file (metadata,
+                                                   "nie:title",
+                                                   md.title,
+                                                   uri,
+                                                   NULL);
 
        if (md.make || md.model) {
-               gchar *equip_uri;
-
-               equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                             md.make ? md.make : "",
-                                                             md.model ? md.model : "");
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               TrackerResource *equipment = tracker_extract_new_equipment (md.make, md.model);
 
-               tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:Equipment");
+               tracker_resource_set_relation (metadata, "nfo:equipment", equipment);
 
-               if (md.make) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.make);
-               }
-               if (md.model) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.model);
-               }
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-               tracker_sparql_builder_object_iri (metadata, equip_uri);
-               g_free (equip_uri);
+               g_object_unref (equipment);
        }
 
        if (md.artist) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               TrackerResource *artist = tracker_extract_new_contact (md.artist);
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
+               tracker_resource_set_relation (metadata, "nco:contributor", artist);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (artist);
        }
 
        if (md.orientation) {
-               tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-               tracker_sparql_builder_object_unvalidated (metadata, md.orientation);
+               tracker_resource_set_string (metadata, "nfo:orientation", md.orientation);
        }
 
        if (md.exposure_time) {
-               tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-               tracker_sparql_builder_object_unvalidated (metadata, md.exposure_time);
+               tracker_resource_set_string (metadata, "nmm:exposureTime", md.exposure_time);
        }
 
        if (md.iso_speed_ratings) {
-               tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-               tracker_sparql_builder_object_unvalidated (metadata, md.iso_speed_ratings);
+               tracker_resource_set_string (metadata, "nmm:isoSpeed", md.iso_speed_ratings);
        }
 
        if (md.white_balance) {
-               tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-               tracker_sparql_builder_object_unvalidated (metadata, md.white_balance);
+               tracker_resource_set_string (metadata, "nmm:whiteBalance", md.white_balance);
        }
 
        if (md.fnumber) {
-               tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-               tracker_sparql_builder_object_unvalidated (metadata, md.fnumber);
+               tracker_resource_set_string (metadata, "nmm:fnumber", md.fnumber);
        }
 
        if (md.flash) {
-               tracker_sparql_builder_predicate (metadata, "nmm:flash");
-               tracker_sparql_builder_object_unvalidated (metadata, md.flash);
-       }
+               tracker_resource_set_string (metadata, "nmm:flash", md.flash); }
 
        if (md.focal_length) {
-               tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-               tracker_sparql_builder_object_unvalidated (metadata, md.focal_length);
+               tracker_resource_set_string (metadata, "nmm:focalLength", md.focal_length);
        }
 
        if (md.metering_mode) {
-               tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-               tracker_sparql_builder_object_unvalidated (metadata, md.metering_mode);
+               tracker_resource_set_string (metadata, "nmm:meteringMode", md.metering_mode);
        }
 
 
@@ -529,8 +454,7 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        }
 
        if (xd->rating) {
-               tracker_sparql_builder_predicate (metadata, "nao:numericRating");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
+               tracker_resource_set_string (metadata, "nao:numericRating", xd->rating);
        }
 
        if (xd->subject) {
@@ -538,207 +462,91 @@ read_metadata (TrackerSparqlBuilder *preupdate,
        }
 
        if (xd->publisher) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
+               TrackerResource *publisher = tracker_extract_new_contact (xd->publisher);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               tracker_resource_set_relation (metadata, "nco:creator", publisher);
 
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (publisher);
        }
 
        if (xd->type) {
-               tracker_sparql_builder_predicate (metadata, "dc:type");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->type);
+               tracker_resource_set_string (metadata, "dc:type", xd->type);
        }
 
        if (xd->format) {
-               tracker_sparql_builder_predicate (metadata, "dc:format");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->format);
+               tracker_resource_set_string (metadata, "dc:format", xd->format);
        }
 
        if (xd->identifier) {
-               tracker_sparql_builder_predicate (metadata, "dc:identifier");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
+               tracker_resource_set_string (metadata, "dc:identifier", xd->identifier);
        }
 
        if (xd->source) {
-               tracker_sparql_builder_predicate (metadata, "dc:source");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->source);
+               tracker_resource_set_string (metadata, "dc:source", xd->source);
        }
 
        if (xd->language) {
-               tracker_sparql_builder_predicate (metadata, "dc:language");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->language);
+               tracker_resource_set_string (metadata, "dc:language", xd->language);
        }
 
        if (xd->relation) {
-               tracker_sparql_builder_predicate (metadata, "dc:relation");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
+               tracker_resource_set_string (metadata, "dc:relation", xd->relation);
        }
 
        if (xd->coverage) {
-               tracker_sparql_builder_predicate (metadata, "dc:coverage");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
+               tracker_resource_set_string (metadata, "dc:coverage", xd->coverage);
        }
 
        if (xd->address || xd->state || xd->country || xd->city ||
            xd->gps_altitude || xd->gps_latitude || xd-> gps_longitude) {
 
-               tracker_sparql_builder_predicate (metadata, "slo:location");
-
-               tracker_sparql_builder_object_blank_open (metadata); /* GeoLocation */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
-
-               if (xd->address || xd->state || xd->country || xd->city)  {
-                       gchar *addruri;
-
-                       addruri = tracker_sparql_get_uuid_urn ();
-
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, addruri);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, addruri);
-
-                       g_free (addruri);
-
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
-
-                       if (xd->address) {
-                         tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                         tracker_sparql_builder_object_unvalidated (preupdate, xd->address);
-                       }
-
-                       if (xd->state) {
-                         tracker_sparql_builder_predicate (preupdate, "nco:region");
-                         tracker_sparql_builder_object_unvalidated (preupdate, xd->state);
-                       }
-
-                       if (xd->city) {
-                         tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                         tracker_sparql_builder_object_unvalidated (preupdate, xd->city);
-                       }
-
-                       if (xd->country) {
-                         tracker_sparql_builder_predicate (preupdate, "nco:country");
-                         tracker_sparql_builder_object_unvalidated (preupdate, xd->country);
-                       }
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
+               TrackerResource *location = tracker_extract_new_location (xd->address,
+                       xd->state, xd->city, xd->country, xd->gps_altitude,
+                       xd->gps_latitude, xd-> gps_longitude);
+               
+               tracker_resource_set_relation (metadata, "slo:location", location);
 
-               if (xd->gps_altitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_altitude);
-               }
-
-               if (xd->gps_latitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_latitude);
-               }
-
-               if (xd->gps_longitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, xd->gps_longitude);
-               }
-
-               tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+               g_object_unref (location);
        }
 
        if (xd->gps_direction) {
-               tracker_sparql_builder_predicate (metadata, "nfo:heading");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->gps_direction);
+               tracker_resource_set_string(metadata, "nfo:heading", xd->gps_direction);
        }
 
        if (ed->x_resolution) {
                gdouble value;
 
                value = ed->resolution_unit != 3 ? g_strtod (ed->x_resolution, NULL) : g_strtod 
(ed->x_resolution, NULL) * CM_TO_INCH;
-               tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:horizontalResolution", value);
        }
 
        if (ed->y_resolution) {
                gdouble value;
 
                value = ed->resolution_unit != 3 ? g_strtod (ed->y_resolution, NULL) : g_strtod 
(ed->y_resolution, NULL) * CM_TO_INCH;
-               tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:verticalResolution", value);
        }
 
        if (xd->regions) {
-               tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
+               tracker_xmp_apply_regions_to_resource (metadata, xd);
        }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *escaped, *subject;
+               TrackerResource *tag;
                const gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               subject = g_strdup_printf ("_:tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject (preupdate, subject);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_append (preupdate,
-                                              "WHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
-
-               /* associate file with tag */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject_iri (preupdate, urn);
-               tracker_sparql_builder_predicate (preupdate, "nao:hasTag");
-               tracker_sparql_builder_object (preupdate, "?tag");
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject (preupdate, "?tag");
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_where_close (preupdate);
-
-               g_free (subject);
-               g_free (escaped);
+
+               tag = tracker_extract_new_tag (p);
+
+               tracker_resource_set_relation (metadata, "nao:hasTag", tag);
+
+               g_object_unref (tag);
        }
        g_ptr_array_free (keywords, TRUE);
 
        if (g_strcmp0(pd.software, "gnome-screenshot") == 0) {
-               tracker_sparql_builder_predicate (metadata, "nie:isPartOf");
-               tracker_sparql_builder_object (metadata, "nfo:image-category-screenshot");
+               tracker_resource_set_string (metadata, "nie:isPartOf", "nfo:image-category-screenshot");
        }
 
        tracker_exif_free (ed);
@@ -783,6 +591,7 @@ guess_dlna_profile (gint          depth,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
+       TrackerResource *metadata;
        goffset size;
        FILE *f;
        png_structp png_ptr;
@@ -793,8 +602,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        png_uint_32 width, height;
        gint bit_depth, color_type;
        gint interlace_type, compression_type, filter_type;
-       const gchar *dlna_profile, *dlna_mimetype, *graph, *urn;
-       TrackerSparqlBuilder *preupdate, *metadata;
+       const gchar *dlna_profile, *dlna_mimetype;
        gchar *filename, *uri;
        GFile *file;
 
@@ -802,11 +610,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        filename = g_file_get_path (file);
        size = tracker_file_get_size (filename);
 
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-       urn = tracker_extract_info_get_urn (info);
-
        if (size < 64) {
                return FALSE;
        }
@@ -884,30 +687,29 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
 
        png_read_end (png_ptr, end_ptr);
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_object (metadata, "nmm:Photo");
+       metadata = tracker_resource_new (NULL);
+
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:Photo");
 
        uri = g_file_get_uri (file);
 
-       read_metadata (preupdate, metadata, png_ptr, info_ptr, end_ptr, uri, graph, urn);
+       read_metadata (metadata, png_ptr, info_ptr, end_ptr, uri);
        g_free (uri);
 
-       tracker_sparql_builder_predicate (metadata, "nfo:width");
-       tracker_sparql_builder_object_int64 (metadata, width);
-
-       tracker_sparql_builder_predicate (metadata, "nfo:height");
-       tracker_sparql_builder_object_int64 (metadata, height);
+       tracker_resource_set_int64 (metadata, "nfo:width", width);
+       tracker_resource_set_int64 (metadata, "nfo:height", height);
 
        if (guess_dlna_profile (bit_depth, width, height, &dlna_profile, &dlna_mimetype)) {
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
-               tracker_sparql_builder_object_string (metadata, dlna_profile);
-               tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
-               tracker_sparql_builder_object_string (metadata, dlna_mimetype);
+               tracker_resource_set_string (metadata, "nmm:dlnaProfile", dlna_profile);
+               tracker_resource_set_string (metadata, "nmm:dlnaMime", dlna_mimetype);
        }
 
        png_destroy_read_struct (&png_ptr, &info_ptr, &end_ptr);
        tracker_file_close (f, FALSE);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-ps.c b/src/tracker-extract/tracker-extract-ps.c
index f9580e9..aa3f62f 100644
--- a/src/tracker-extract/tracker-extract-ps.c
+++ b/src/tracker-extract/tracker-extract-ps.c
@@ -100,11 +100,10 @@ date_to_iso8601 (const gchar *date)
        return NULL;
 }
 
-static void
-extract_ps_from_filestream (FILE *f,
-                            TrackerSparqlBuilder *preupdate,
-                            TrackerSparqlBuilder *metadata)
+static TrackerResource *
+extract_ps_from_filestream (FILE *f)
 {
+       TrackerResource *metadata;
        gchar *line;
        gsize length;
        gssize read_char;
@@ -114,8 +113,8 @@ extract_ps_from_filestream (FILE *f,
        line = NULL;
        length = 0;
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PaginatedTextDocument");
 
        /* 20 MiB should be enough! (original safe limit) */
        accum = 0;
@@ -141,26 +140,19 @@ extract_ps_from_filestream (FILE *f,
                line[read_char - 1] = '\0';  /* overwrite '\n' char */
 
                if (!header_finished && strncmp (line, "%%Copyright:", 12) == 0) {
-                       tracker_sparql_builder_predicate (metadata, "nie:copyright");
-                       tracker_sparql_builder_object_unvalidated (metadata, line + 13);
+                       tracker_resource_set_string (metadata, "nie:copyright", line + 13);
                } else if (!header_finished && strncmp (line, "%%Title:", 8) == 0) {
-                       tracker_sparql_builder_predicate (metadata, "nie:title");
-                       tracker_sparql_builder_object_unvalidated (metadata, line + 9);
+                       tracker_resource_set_string (metadata, "nie:title", line + 9);
                } else if (!header_finished && strncmp (line, "%%Creator:", 10) == 0) {
-                       tracker_sparql_builder_predicate (metadata, "nco:creator");
-                       tracker_sparql_builder_object_blank_open (metadata);
-                       tracker_sparql_builder_predicate (metadata, "a");
-                       tracker_sparql_builder_object (metadata, "nco:Contact");
-                       tracker_sparql_builder_predicate (metadata, "nco:fullname");
-                       tracker_sparql_builder_object_unvalidated (metadata, line + 11);
-                       tracker_sparql_builder_object_blank_close (metadata);
+                       TrackerResource *creator = tracker_extract_new_contact (line + 11);
+                       tracker_resource_set_relation (metadata, "nco:creator", creator);
+                       g_object_unref (creator);
                } else if (!header_finished && strncmp (line, "%%CreationDate:", 15) == 0) {
                        gchar *date;
 
                        date = date_to_iso8601 (line + 16);
                        if (date) {
-                               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-                               tracker_sparql_builder_object_unvalidated (metadata, date);
+                               tracker_resource_set_string (metadata, "nie:contentCreated", date);
                                g_free (date);
                        }
                } else if (strncmp (line, "%%Pages:", 8) == 0) {
@@ -170,8 +162,7 @@ extract_ps_from_filestream (FILE *f,
                                gint64 page_count;
 
                                page_count = g_ascii_strtoll (line + 9, NULL, 10);
-                               tracker_sparql_builder_predicate (metadata, "nfo:pageCount");
-                               tracker_sparql_builder_object_int64 (metadata, page_count);
+                               tracker_resource_set_int (metadata, "nfo:pageCount", page_count);
                        }
                } else if (strncmp (line, "%%EndComments", 14) == 0) {
                        header_finished = TRUE;
@@ -186,15 +177,16 @@ extract_ps_from_filestream (FILE *f,
        if (line) {
                g_free (line);
        }
+
+       return metadata;
 }
 
 
 
-static void
-extract_ps (const gchar          *uri,
-            TrackerSparqlBuilder *preupdate,
-            TrackerSparqlBuilder *metadata)
+static TrackerResource *
+extract_ps (const gchar          *uri)
 {
+       TrackerResource *metadata;
        FILE *f;
        gchar *filename;
 
@@ -203,14 +195,16 @@ extract_ps (const gchar          *uri,
        g_free (filename);
 
        if (!f) {
-               return;
+               return NULL;
        }
 
        /* Extract from filestream! */
        g_debug ("Extracting PS '%s'...", uri);
-       extract_ps_from_filestream (f, preupdate, metadata);
+       metadata = extract_ps_from_filestream (f);
 
        tracker_file_close (f, FALSE);
+
+       return metadata;
 }
 
 #ifdef USING_UNZIPPSFILES
@@ -254,11 +248,10 @@ spawn_child_func (gpointer user_data)
        }
 }
 
-static void
-extract_ps_gz (const gchar          *uri,
-               TrackerSparqlBuilder *preupdate,
-               TrackerSparqlBuilder *metadata)
+static TrackerResource *
+extract_ps_gz (const gchar          *uri)
 {
+       TrackerResource *metadata = NULL;
        FILE *fz;
        gint fdz;
        const gchar *argv[4];
@@ -299,7 +292,7 @@ extract_ps_gz (const gchar          *uri,
        else
        {
                g_debug ("Extracting compressed PS '%s'...", uri);
-               extract_ps_from_filestream (fz, preupdate, metadata);
+               metadata = extract_ps_from_filestream (fz);
 #ifdef HAVE_POSIX_FADVISE
                posix_fadvise (fdz, 0, 0, POSIX_FADV_DONTNEED);
 #endif /* HAVE_POSIX_FADVISE */
@@ -307,6 +300,8 @@ extract_ps_gz (const gchar          *uri,
        }
 
        g_free (filename);
+
+       return metadata;
 }
 
 #endif /* USING_UNZIPPSFILES */
@@ -314,28 +309,30 @@ extract_ps_gz (const gchar          *uri,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *preupdate, *metadata;
-       const gchar *mimetype;
+       TrackerResource *metadata;
        GFile *file;
        gchar *uri;
-
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       mimetype = tracker_extract_info_get_mimetype (info);
+       const char *mimetype;
 
        file = tracker_extract_info_get_file (info);
+       mimetype = tracker_extract_info_get_mimetype (info);
        uri = g_file_get_uri (file);
 
 #ifdef USING_UNZIPPSFILES
        if (strcmp (mimetype, "application/x-gzpostscript") == 0) {
-               extract_ps_gz (uri, preupdate, metadata);
+               metadata = extract_ps_gz (uri);
        } else
 #endif /* USING_UNZIPPSFILES */
        {
-               extract_ps (uri, preupdate, metadata);
+               metadata = extract_ps (uri);
        }
 
        g_free (uri);
 
+       if (metadata) {
+               tracker_extract_info_set_resource (info, metadata);
+               g_object_unref (metadata);
+       }
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-text.c b/src/tracker-extract/tracker-extract-text.c
index 594a288..857daa4 100644
--- a/src/tracker-extract/tracker-extract-text.c
+++ b/src/tracker-extract/tracker-extract-text.c
@@ -91,24 +91,26 @@ tracker_extract_module_init (TrackerModuleThreadAwareness  *thread_awareness_ret
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *metadata;
        TrackerConfig *config;
        gchar *content;
 
        config = tracker_main_get_config ();
-       metadata = tracker_extract_info_get_metadata_builder (info);
 
        content = get_file_content (tracker_extract_info_get_file (info),
                                    tracker_config_get_max_bytes (config));
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PlainTextDocument");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:PlainTextDocument");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:FileDataObject");
 
        if (content) {
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, content);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", content);
                g_free (content);
        }
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-tiff.c b/src/tracker-extract/tracker-extract-tiff.c
index d1c6d50..1cd9a9c 100644
--- a/src/tracker-extract/tracker-extract-tiff.c
+++ b/src/tracker-extract/tracker-extract-tiff.c
@@ -253,6 +253,7 @@ tag_to_string (TIFF    *image,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
+       TrackerResource *metadata;
        TIFF *image;
        TrackerXmpData *xd = NULL;
        TrackerIptcData *id = NULL;
@@ -265,8 +266,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        GPtrArray *keywords;
        guint i;
        GFile *file;
-       TrackerSparqlBuilder *metadata, *preupdate;
-       const gchar *graph, *urn;
        int fd;
 
 #ifdef HAVE_LIBIPTCDATA
@@ -282,11 +281,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
 
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-       urn = tracker_extract_info_get_urn (info);
-
        fd = tracker_file_open_fd (filename);
 
        if (fd == -1) {
@@ -304,9 +298,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:Image");
-       tracker_sparql_builder_object (metadata, "nmm:Photo");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Image");
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:Photo");
 
        uri = g_file_get_uri (file);
 
@@ -410,18 +404,15 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        keywords = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
 
        if (ed->user_comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, ed->user_comment);
+               tracker_resource_set_string (metadata, "nie:comment", ed->user_comment);
        }
 
        if (md.x_dimension) {
-               tracker_sparql_builder_predicate (metadata, "nfo:width");
-               tracker_sparql_builder_object_unvalidated (metadata, md.x_dimension);
+               tracker_resource_set_string (metadata, "nfo:width", md.x_dimension);
        }
 
        if (md.y_dimension) {
-               tracker_sparql_builder_predicate (metadata, "nfo:height");
-               tracker_sparql_builder_object_unvalidated (metadata, md.y_dimension);
+               tracker_resource_set_string (metadata, "nfo:height", md.y_dimension);
        }
 
        if (xd->keywords) {
@@ -437,178 +428,74 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (xd->publisher) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:publisher");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               TrackerResource *publisher = tracker_extract_new_contact (xd->publisher);
+               tracker_resource_set_relation (metadata, "nco:publisher", publisher);
+               g_object_unref (publisher);
        }
 
        if (xd->type) {
-               tracker_sparql_builder_predicate (metadata, "dc:type");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->type);
+               tracker_resource_set_string (metadata, "dc:type", xd->type);
        }
 
        if (xd->format) {
-               tracker_sparql_builder_predicate (metadata, "dc:format");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->format);
+               tracker_resource_set_string (metadata, "dc:format", xd->format);
        }
 
        if (xd->identifier) {
-               tracker_sparql_builder_predicate (metadata, "dc:identifier");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->identifier);
+               tracker_resource_set_string (metadata, "dc:identifier", xd->identifier);
        }
 
        if (xd->source) {
-               tracker_sparql_builder_predicate (metadata, "dc:source");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->source);
+               tracker_resource_set_string (metadata, "dc:source", xd->source);
        }
 
        if (xd->language) {
-               tracker_sparql_builder_predicate (metadata, "dc:language");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->language);
+               tracker_resource_set_string (metadata, "dc:language", xd->language);
        }
 
        if (xd->relation) {
-               tracker_sparql_builder_predicate (metadata, "dc:relation");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->relation);
+               tracker_resource_set_string (metadata, "dc:relation", xd->relation);
        }
 
        if (xd->coverage) {
-               tracker_sparql_builder_predicate (metadata, "dc:coverage");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->coverage);
+               tracker_resource_set_string (metadata, "dc:coverage", xd->coverage);
        }
 
        if (xd->rating) {
-               tracker_sparql_builder_predicate (metadata, "nao:numericRating");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->rating);
+               tracker_resource_set_string (metadata, "nao:numericRating", xd->rating);
        }
 
        if (xd->license) {
-               tracker_sparql_builder_predicate (metadata, "nie:license");
-               tracker_sparql_builder_object_unvalidated (metadata, xd->license);
+               tracker_resource_set_string (metadata, "nie:license", xd->license);
        }
 
-        if (xd->regions) {
-               tracker_xmp_apply_regions (preupdate, metadata, graph, xd);
-        }
+       if (xd->regions) {
+               tracker_xmp_apply_regions_to_resource (metadata, xd);
+       }
 
        if (md.address || md.state || md.country || md.city ||
            md.gps_altitude || md.gps_latitude || md.gps_longitude) {
+               TrackerResource *location;
 
-               tracker_sparql_builder_predicate (metadata, "slo:location");
-
-               tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "slo:GeoLocation");
-
-               if (md.address || md.state || md.country || md.city) {
-                       gchar *addruri;
-
-                       addruri = tracker_sparql_get_uuid_urn ();
-
-                       tracker_sparql_builder_predicate (metadata, "slo:postalAddress");
-                       tracker_sparql_builder_object_iri (metadata, addruri);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, addruri);
+               location = tracker_extract_new_location (md.address, md.state,
+                               md.city, md.country, md.gps_altitude, md.gps_latitude,
+                               md.gps_longitude);
 
-                       g_free (addruri);
-
-                       tracker_sparql_builder_predicate (preupdate, "a");
-                       tracker_sparql_builder_object (preupdate, "nco:PostalAddress");
-
-                       if (md.address) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:streetAddress");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.address);
-                       }
-
-                       if (md.state) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:region");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.state);
-                       }
-
-                       if (md.city) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:locality");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.city);
-                       }
-
-                       if (md.country) {
-                               tracker_sparql_builder_predicate (preupdate, "nco:country");
-                               tracker_sparql_builder_object_unvalidated (preupdate, md.country);
-                       }
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-
-               if (md.gps_altitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:altitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_altitude);
-               }
-
-               if (md.gps_latitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:latitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_latitude);
-               }
-
-               if (md.gps_longitude) {
-                       tracker_sparql_builder_predicate (metadata, "slo:longitude");
-                       tracker_sparql_builder_object_unvalidated (metadata, md.gps_longitude);
-               }
+               tracker_resource_set_relation (metadata, "slo:location", location);
 
-               tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */
+               g_object_unref (location);
        }
 
        if (md.gps_direction) {
-               tracker_sparql_builder_predicate (metadata, "nfo:heading");
-               tracker_sparql_builder_object_unvalidated (metadata, md.gps_direction);
+               tracker_resource_set_string (metadata, "nfo:heading", md.gps_direction);
        }
 
        if (id->contact) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", id->contact);
+               TrackerResource *contact = tracker_extract_new_contact (id->contact);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, id->contact);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               tracker_resource_set_relation (metadata, "nco:contributor", contact);
 
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (contact);
        }
 
        if (id->keywords) {
@@ -616,185 +503,86 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        for (i = 0; i < keywords->len; i++) {
-               gchar *escaped, *subject;
+               TrackerResource *tag;
                const gchar *p;
 
                p = g_ptr_array_index (keywords, i);
-               escaped = tracker_sparql_escape_string (p);
-               subject = g_strdup_printf ("_:tag%d", i + 1);
-
-               /* ensure tag with specified label exists */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject (preupdate, subject);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_append (preupdate,
-                                              "WHERE { FILTER (NOT EXISTS { "
-                                              "?tag a nao:Tag ; nao:prefLabel \"");
-               tracker_sparql_builder_append (preupdate, escaped);
-               tracker_sparql_builder_append (preupdate,
-                                              "\" }) }\n");
-
-               /* associate file with tag */
-               tracker_sparql_builder_insert_open (preupdate, graph);
-               tracker_sparql_builder_subject_iri (preupdate, urn);
-               tracker_sparql_builder_predicate (preupdate, "nao:hasTag");
-               tracker_sparql_builder_object (preupdate, "?tag");
-               tracker_sparql_builder_insert_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject (preupdate, "?tag");
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nao:Tag");
-               tracker_sparql_builder_predicate (preupdate, "nao:prefLabel");
-               tracker_sparql_builder_object_unvalidated (preupdate, escaped);
-               tracker_sparql_builder_where_close (preupdate);
-
-               g_free (subject);
-               g_free (escaped);
+               tag = tracker_extract_new_tag (p);
+
+               tracker_resource_set_relation (metadata, "nao:hasTag", tag);
+
+               g_object_unref (tag);
        }
        g_ptr_array_free (keywords, TRUE);
 
        if (md.make || md.model) {
-               gchar *equip_uri;
-
-               equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:",
-                                                             md.make ? md.make : "",
-                                                             md.model ? md.model : "");
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, equip_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nfo:Equipment");
-
-               if (md.make) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.make);
-               }
-               if (md.model) {
-                       tracker_sparql_builder_predicate (preupdate, "nfo:model");
-                       tracker_sparql_builder_object_unvalidated (preupdate, md.model);
-               }
+               TrackerResource *equipment = tracker_extract_new_equipment (md.make, md.model);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               tracker_resource_set_relation (metadata, "nfo:equipment", equipment);
 
-               tracker_sparql_builder_predicate (metadata, "nfo:equipment");
-               tracker_sparql_builder_object_iri (metadata, equip_uri);
-               g_free (equip_uri);
+               g_object_unref (equipment);
        }
 
-       tracker_guarantee_title_from_file (metadata,
-                                          "nie:title",
-                                          md.title,
-                                          uri,
-                                          NULL);
+       tracker_guarantee_resource_title_from_file (metadata,
+                                                   "nie:title",
+                                                   md.title,
+                                                   uri,
+                                                   NULL);
 
        if (md.orientation) {
-               tracker_sparql_builder_predicate (metadata, "nfo:orientation");
-               tracker_sparql_builder_object_unvalidated (metadata, md.orientation);
+               tracker_resource_set_string (metadata, "nfo:orientation", md.orientation);
        }
 
        if (md.copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
+               tracker_resource_set_string (metadata, "nie:copyright", md.copyright);
        }
 
        if (md.white_balance) {
-               tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance");
-               tracker_sparql_builder_object_unvalidated (metadata, md.white_balance);
+               tracker_resource_set_string (metadata, "nmm:whiteBalance", md.white_balance);
        }
 
        if (md.fnumber) {
-               tracker_sparql_builder_predicate (metadata, "nmm:fnumber");
-               tracker_sparql_builder_object_unvalidated (metadata, md.fnumber);
+               tracker_resource_set_string (metadata, "nmm:fnumber", md.fnumber);
        }
 
        if (md.flash) {
-               tracker_sparql_builder_predicate (metadata, "nmm:flash");
-               tracker_sparql_builder_object_unvalidated (metadata, md.flash);
-       }
+               tracker_resource_set_string (metadata, "nmm:flash", md.flash); }
 
        if (md.focal_length) {
-               tracker_sparql_builder_predicate (metadata, "nmm:focalLength");
-               tracker_sparql_builder_object_unvalidated (metadata, md.focal_length);
+               tracker_resource_set_string (metadata, "nmm:focalLength", md.focal_length);
        }
 
        if (md.artist) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+               TrackerResource *artist = tracker_extract_new_contact (md.artist);
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.artist);
+               tracker_resource_set_relation (metadata, "nco:contributor", artist);
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nco:contributor");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (artist);
        }
 
        if (md.exposure_time) {
-               tracker_sparql_builder_predicate (metadata, "nmm:exposureTime");
-               tracker_sparql_builder_object_unvalidated (metadata, md.exposure_time);
+               tracker_resource_set_string (metadata, "nmm:exposureTime", md.exposure_time);
        }
 
        if (md.iso_speed_ratings) {
-               tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed");
-               tracker_sparql_builder_object_unvalidated (metadata, md.iso_speed_ratings);
+               tracker_resource_set_string (metadata, "nmm:isoSpeed", md.iso_speed_ratings);
        }
 
-       tracker_guarantee_date_from_file_mtime (metadata,
-                                               "nie:contentCreated",
-                                               md.date,
-                                               uri);
+       tracker_guarantee_resource_date_from_file_mtime (metadata,
+                                                        "nie:contentCreated",
+                                                        md.date,
+                                                        uri);
 
        if (md.description) {
-               tracker_sparql_builder_predicate (metadata, "nie:description");
-               tracker_sparql_builder_object_unvalidated (metadata, md.description);
+               tracker_resource_set_string (metadata, "nie:description", md.description);
        }
 
        if (md.metering_mode) {
-               tracker_sparql_builder_predicate (metadata, "nmm:meteringMode");
-               tracker_sparql_builder_object_unvalidated (metadata, md.metering_mode);
+               tracker_resource_set_string (metadata, "nmm:meteringMode", md.metering_mode);
        }
 
        if (md.creator) {
-               gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nco:Contact");
-               tracker_sparql_builder_predicate (preupdate, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
+               TrackerResource *creator = tracker_extract_new_contact (md.creator);
 
                /* NOTE: We only have affiliation with
                 * nco:PersonContact and we are using
@@ -819,25 +607,23 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                /*      tracker_sparql_builder_object (metadata, "_:affiliation_by_line"); */
                /* } */
 
-               tracker_sparql_builder_predicate (metadata, "nco:creator");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               tracker_resource_set_relation (metadata, "nco:creator", creator);
+
+               g_object_unref (creator);
        }
 
        if (ed->x_resolution) {
                gdouble value;
 
                value = ed->resolution_unit != 3 ? g_strtod (ed->x_resolution, NULL) : g_strtod 
(ed->x_resolution, NULL) * CM_TO_INCH;
-               tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:horizontalResolution", value);
        }
 
        if (ed->y_resolution) {
                gdouble value;
 
                value = ed->resolution_unit != 3 ? g_strtod (ed->y_resolution, NULL) : g_strtod 
(ed->y_resolution, NULL) * CM_TO_INCH;
-               tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution");
-               tracker_sparql_builder_object_double (metadata, value);
+               tracker_resource_set_double (metadata, "nfo:verticalResolution", value);
        }
 
        tiff_data_free (&td);
@@ -847,5 +633,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        g_free (uri);
        close (fd);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-vorbis.c b/src/tracker-extract/tracker-extract-vorbis.c
index 0dfdaec..9c2b778 100644
--- a/src/tracker-extract/tracker-extract-vorbis.c
+++ b/src/tracker-extract/tracker-extract-vorbis.c
@@ -37,8 +37,8 @@
 #include <libtracker-extract/tracker-extract.h>
 
 typedef struct {
-       const gchar *creator;
-       gchar *creator_uri;
+       const gchar *creator_name;
+       TrackerResource *creator;
 } MergeData;
 
 typedef struct {
@@ -93,7 +93,7 @@ ogg_get_comment (vorbis_comment *vc,
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *preupdate, *metadata;
+       TrackerResource *metadata;
        VorbisData vd = { 0 };
        MergeData md = { 0 };
        FILE *f;
@@ -104,17 +104,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        unsigned int bitrate;
        gint time;
        GFile *file;
-       const gchar *graph;
 
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
        f = tracker_file_open (filename);
        g_free (filename);
 
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-       graph = tracker_extract_info_get_graph (info);
-
        if (!f) {
                return FALSE;
        }
@@ -124,9 +119,9 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
-       tracker_sparql_builder_object (metadata, "nfo:Audio");
+       metadata = tracker_resource_new (NULL);
+       tracker_resource_add_uri (metadata, "rdf:type", "nmm:MusicPiece");
+       tracker_resource_add_uri (metadata, "rdf:type", "nfo:Audio");
 
        if ((comment = ov_comment (&vf, -1)) != NULL) {
                gchar *date;
@@ -170,207 +165,50 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                vorbis_comment_clear (comment);
        }
 
-       md.creator = tracker_coalesce_strip (3, vd.artist, vd.album_artist, vd.performer);
-
-       if (md.creator) {
-               /* NOTE: This must be created before vd.album is evaluated */
-               md.creator_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.creator);
+       md.creator_name = tracker_coalesce_strip (3, vd.artist, vd.album_artist, vd.performer);
 
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
+       if (md.creator_name) {
+               md.creator = tracker_extract_new_artist (md.creator_name);
 
-               tracker_sparql_builder_subject_iri (preupdate, md.creator_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:Artist");
-               tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
-               tracker_sparql_builder_object_unvalidated (preupdate, md.creator);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
-
-               tracker_sparql_builder_predicate (metadata, "nmm:performer");
-               tracker_sparql_builder_object_iri (metadata, md.creator_uri);
+               tracker_resource_set_relation (metadata, "nmm:performer", md.creator);
        }
 
        if (vd.album) {
-                gchar *uri;
-                if (vd.album_artist) {
-                        uri = tracker_sparql_escape_uri_printf ("urn:album:%s:%s", vd.album, 
vd.album_artist);
-                } else {
-                        uri = tracker_sparql_escape_uri_printf ("urn:album:%s", vd.album);
-                }
-               gchar *album_disc_uri;
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
+               TrackerResource *album, *album_disc, *album_artist;
+
+               if (vd.album_artist) {
+                       album_artist = tracker_extract_new_artist (vd.album_artist);
+               } else if (md.creator) {
+                       album_artist = g_object_ref (md.creator);
+               } else {
+                       album_artist = NULL;
                }
 
-               tracker_sparql_builder_subject_iri (preupdate, uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum");
-               /* FIXME: nmm:albumTitle is now deprecated
-                * tracker_sparql_builder_predicate (preupdate, "nie:title");
-                */
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle");
-               tracker_sparql_builder_object_unvalidated (preupdate, vd.album);
-
-               if (md.creator_uri) {
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumArtist");
-                       tracker_sparql_builder_object_iri (preupdate, md.creator_uri);
-               }
+               album_disc = tracker_extract_new_music_album_disc (vd.album,
+                                                                  album_artist,
+                                                                  vd.disc_number ? atoi(vd.disc_number) : 1);
+
+               g_object_unref (album_artist);
+
+               album = tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum");
 
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
-               }
-               tracker_sparql_builder_insert_close (preupdate);
 
                if (vd.track_count) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
-                       tracker_sparql_builder_object_unvalidated (preupdate, vd.track_count);
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
+                       tracker_resource_set_string (album, "nmm:albumTrackCount", vd.track_count);
                }
 
                if (vd.album_gain) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumGain");
-                       tracker_sparql_builder_object_double (preupdate, atof (vd.album_gain));
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
+                       tracker_resource_set_double (album, "nmm:albumGain", atof (vd.album_gain));
                }
 
                if (vd.album_peak_gain) {
-                       tracker_sparql_builder_delete_open (preupdate, NULL);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_delete_close (preupdate);
-
-                       tracker_sparql_builder_where_open (preupdate);
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_variable (preupdate, "unknown");
-                       tracker_sparql_builder_where_close (preupdate);
-
-                       tracker_sparql_builder_insert_open (preupdate, NULL);
-                       if (graph) {
-                               tracker_sparql_builder_graph_open (preupdate, graph);
-                       }
-
-                       tracker_sparql_builder_subject_iri (preupdate, uri);
-                       tracker_sparql_builder_predicate (preupdate, "nmm:albumPeakGain");
-                       tracker_sparql_builder_object_double (preupdate, atof (vd.album_peak_gain));
-
-                       if (graph) {
-                               tracker_sparql_builder_graph_close (preupdate);
-                       }
-                       tracker_sparql_builder_insert_close (preupdate);
-               }
-
-                if (vd.album_artist) {
-                        album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:%s:Disc%d",
-                                                                           vd.album, vd.album_artist,
-                                                                           vd.disc_number ? 
atoi(vd.disc_number) : 1);
-                } else {
-                        album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
-                                                                           vd.album,
-                                                                           vd.disc_number ? 
atoi(vd.disc_number) : 1);
-                }
-
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_delete_open (preupdate, NULL);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_delete_close (preupdate);
-               tracker_sparql_builder_where_open (preupdate);
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_variable (preupdate, "unknown");
-               tracker_sparql_builder_where_close (preupdate);
-
-               tracker_sparql_builder_insert_open (preupdate, NULL);
-               if (graph) {
-                       tracker_sparql_builder_graph_open (preupdate, graph);
-               }
-
-               tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
-               tracker_sparql_builder_predicate (preupdate, "a");
-               tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc");
-               tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
-               tracker_sparql_builder_object_int64 (preupdate, vd.disc_number ? atoi (vd.disc_number) : 1);
-               tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
-               tracker_sparql_builder_object_iri (preupdate, uri);
-
-               if (graph) {
-                       tracker_sparql_builder_graph_close (preupdate);
+                       tracker_resource_set_double (album, "nmm:albumPeakGain", atof (vd.album_peak_gain));
                }
-               tracker_sparql_builder_insert_close (preupdate);
 
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc");
-               tracker_sparql_builder_object_iri (metadata, album_disc_uri);
+               tracker_resource_set_relation (metadata, "nmm:musicAlbum", album);
+               tracker_resource_set_relation (metadata, "nmm:musicAlbumDisc", album_disc);
 
-               g_free (album_disc_uri);
-
-               tracker_sparql_builder_predicate (metadata, "nmm:musicAlbum");
-               tracker_sparql_builder_object_iri (metadata, uri);
-               g_free (uri);
+               g_object_unref (album_disc);
        }
 
        g_free (vd.track_count);
@@ -379,14 +217,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        g_free (vd.disc_number);
 
        if (vd.title) {
-               tracker_sparql_builder_predicate (metadata, "nie:title");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.title);
+               tracker_resource_set_string (metadata, "nie:title", vd.title);
                g_free (vd.title);
        }
 
        if (vd.track_number) {
-               tracker_sparql_builder_predicate (metadata, "nmm:trackNumber");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.track_number);
+               tracker_resource_set_string (metadata, "nmm:trackNumber", vd.track_number);
                g_free (vd.track_number);
        }
 
@@ -401,26 +237,22 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (vd.comment) {
-               tracker_sparql_builder_predicate (metadata, "nie:comment");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.comment);
+               tracker_resource_set_string (metadata, "nie:comment", vd.comment);
                g_free (vd.comment);
        }
 
        if (vd.date) {
-               tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.date);
+               tracker_resource_set_string (metadata, "nie:contentCreated", vd.date);
                g_free (vd.date);
        }
 
        if (vd.genre) {
-               tracker_sparql_builder_predicate (metadata, "nfo:genre");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.genre);
+               tracker_resource_set_string (metadata, "nfo:genre", vd.genre);
                g_free (vd.genre);
        }
 
        if (vd.codec) {
-               tracker_sparql_builder_predicate (metadata, "nfo:codec");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.codec);
+               tracker_resource_set_string (metadata, "nfo:codec", vd.codec);
                g_free (vd.codec);
        }
 
@@ -430,14 +262,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (vd.sample_rate) {
-               tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.sample_rate);
+               tracker_resource_set_string (metadata, "nfo:sampleRate", vd.sample_rate);
                g_free (vd.sample_rate);
        }
 
        if (vd.channels) {
-               tracker_sparql_builder_predicate (metadata, "nfo:channels");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.channels);
+               tracker_resource_set_string (metadata, "nfo:channels", vd.channels);
                g_free (vd.channels);
        }
 
@@ -462,20 +292,17 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (vd.lyrics) {
-               tracker_sparql_builder_predicate (metadata, "nie:plainTextContent");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.lyrics);
+               tracker_resource_set_string (metadata, "nie:plainTextContent", vd.lyrics);
                g_free (vd.lyrics);
        }
 
        if (vd.copyright) {
-               tracker_sparql_builder_predicate (metadata, "nie:copyright");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.copyright);
+               tracker_resource_set_string (metadata, "nie:copyright", vd.copyright);
                g_free (vd.copyright);
        }
 
        if (vd.license) {
-               tracker_sparql_builder_predicate (metadata, "nie:license");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.license);
+               tracker_resource_set_string (metadata, "nie:license", vd.license);
                g_free (vd.license);
        }
 
@@ -490,29 +317,22 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
 
        if (vd.publisher) {
-               tracker_sparql_builder_predicate (metadata, "dc:publisher");
+               TrackerResource *publisher = tracker_extract_new_contact (vd.publisher);
 
-               tracker_sparql_builder_object_blank_open (metadata);
-               tracker_sparql_builder_predicate (metadata, "a");
-               tracker_sparql_builder_object (metadata, "nco:Contact");
+               tracker_resource_set_relation (metadata, "dc:publisher", publisher);
 
-               tracker_sparql_builder_predicate (metadata, "nco:fullname");
-               tracker_sparql_builder_object_unvalidated (metadata, vd.publisher);
-               tracker_sparql_builder_object_blank_close (metadata);
-               g_free (vd.publisher);
+               g_object_unref (publisher);
        }
 
        if ((vi = ov_info (&vf, 0)) != NULL ) {
                bitrate = vi->bitrate_nominal / 1000;
 
-               tracker_sparql_builder_predicate (metadata, "nfo:averageBitrate");
-               tracker_sparql_builder_object_int64 (metadata, (gint64) bitrate);
+               tracker_resource_set_int64 (metadata, "nfo:averageBitrate", (gint64) bitrate);
        }
 
        /* Duration */
        if ((time = ov_time_total (&vf, -1)) != OV_EINVAL) {
-               tracker_sparql_builder_predicate (metadata, "nfo:duration");
-               tracker_sparql_builder_object_int64 (metadata, (gint64) time);
+               tracker_resource_set_int64 (metadata, "nfo:duration", (gint64) time);
        }
 
 #ifdef HAVE_LIBMEDIAART
@@ -550,7 +370,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        g_free (vd.album_artist);
        g_free (vd.performer);
 
-       g_free (md.creator_uri);
+       g_object_unref (md.creator);
 
 #ifdef HAVE_POSIX_FADVISE
        posix_fadvise (fileno (f), 0, 0, POSIX_FADV_DONTNEED);
@@ -559,5 +379,8 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        /* NOTE: This calls fclose on the file */
        ov_clear (&vf);
 
+       tracker_extract_info_set_resource (info, metadata);
+       g_object_unref (metadata);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract-xmp.c b/src/tracker-extract/tracker-extract-xmp.c
index 1ba20fb..44c035c 100644
--- a/src/tracker-extract/tracker-extract-xmp.c
+++ b/src/tracker-extract/tracker-extract-xmp.c
@@ -135,23 +135,18 @@ find_orig_uri (const gchar *xmp_filename)
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata, *preupdate;
+       TrackerResource *resource;
        TrackerXmpData *xd = NULL;
        gchar *filename, *uri;
        gchar *contents;
        gsize length = 0;
        GFile *file;
-       const gchar *graph;
        int fd;
        struct stat st;
 
        file = tracker_extract_info_get_file (info);
        filename = g_file_get_path (file);
 
-       graph = tracker_extract_info_get_graph (info);
-       preupdate = tracker_extract_info_get_preupdate_builder (info);
-       metadata = tracker_extract_info_get_metadata_builder (info);
-
        fd = tracker_file_open_fd (filename);
 
        if (fd == -1) {
@@ -202,12 +197,12 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                      original_uri ? original_uri : uri);
 
                if (xd) {
-                       GString *where;
+                       resource = tracker_resource_new (NULL);
+
+                       tracker_xmp_apply_to_resource (resource, xd);
 
-                       where = g_string_new ("");
-                       tracker_xmp_apply (preupdate, metadata, graph, where, uri, xd);
-                       tracker_extract_info_set_where_clause (info, where->str);
-                       g_string_free (where, TRUE);
+                       tracker_extract_info_set_resource (info, resource);
+                       g_object_unref (resource);
                }
 
                g_free (original_uri);
diff --git a/src/tracker-extract/tracker-extract-xps.c b/src/tracker-extract/tracker-extract-xps.c
index 941a600..096bdd1 100644
--- a/src/tracker-extract/tracker-extract-xps.c
+++ b/src/tracker-extract/tracker-extract-xps.c
@@ -27,14 +27,13 @@
 G_MODULE_EXPORT gboolean
 tracker_extract_get_metadata (TrackerExtractInfo *info)
 {
-       TrackerSparqlBuilder *metadata;
+       TrackerResource *resource;
        GXPSDocument *document;
        GXPSFile *xps_file;
        GFile *file;
        gchar *filename;
        GError *error = NULL;
 
-       metadata = tracker_extract_info_get_metadata_builder (info);
        file = tracker_extract_info_get_file (info);
        xps_file = gxps_file_new (file, &error);
        filename = g_file_get_path (file);
@@ -56,14 +55,15 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
-       tracker_sparql_builder_predicate (metadata, "a");
-       tracker_sparql_builder_object (metadata, "nfo:PaginatedTextDocument");
-
-       tracker_sparql_builder_predicate (metadata, "nfo:pageCount");
-       tracker_sparql_builder_object_int64 (metadata, gxps_document_get_n_pages (document));
+       resource = tracker_resource_new (NULL);
+       tracker_resource_add_uri (resource, "rdf:type", "nfo:PaginatedTextDocument");
+       tracker_resource_set_int64 (resource, "nfo:pageCount", gxps_document_get_n_pages (document));
 
        g_object_unref (document);
        g_free (filename);
 
+       tracker_extract_info_set_resource (info, resource);
+       g_object_unref (resource);
+
        return TRUE;
 }
diff --git a/src/tracker-extract/tracker-extract.c b/src/tracker-extract/tracker-extract.c
index a184078..b32f34f 100644
--- a/src/tracker-extract/tracker-extract.c
+++ b/src/tracker-extract/tracker-extract.c
@@ -87,8 +87,6 @@ typedef struct {
        GAsyncResult *res;
        gchar *file;
        gchar *mimetype;
-       gchar *graph;
-       gchar *urn;
 
        TrackerMimetypeInfo *mimetype_handlers;
 
@@ -296,13 +294,11 @@ get_file_metadata (TrackerExtractTask  *task,
        TrackerExtractInfo *info;
        GFile *file;
        gchar *mime_used = NULL;
-       gint items = 0;
-       gboolean success = FALSE;
 
        *info_out = NULL;
 
        file = g_file_new_for_uri (task->file);
-       info = tracker_extract_info_new (file, task->mimetype, task->graph, task->urn);
+       info = tracker_extract_info_new (file, task->mimetype);
        g_object_unref (file);
 
 #ifdef HAVE_LIBMEDIAART
@@ -322,37 +318,25 @@ get_file_metadata (TrackerExtractTask  *task,
         */
        if (mime_used) {
                if (task->cur_func) {
-                       TrackerSparqlBuilder *statements;
-
                        g_debug ("Using %s...",
                                 task->cur_module ?
                                 g_module_name (task->cur_module) :
                                 "Dummy extraction");
 
-                       success = (task->cur_func) (info);
-
-                       statements = tracker_extract_info_get_metadata_builder (info);
-                       items = tracker_sparql_builder_get_length (statements);
-
-                       if (items > 0)
-                               tracker_sparql_builder_insert_close (statements);
-
-                       task->success = success;
+                       task->success = (task->cur_func) (info);
                }
 
                g_free (mime_used);
        }
 
-       g_debug ("Done (%d objects added)\n", items);
-
-       if (!success) {
+       if (!task->success) {
                tracker_extract_info_unref (info);
                info = NULL;
        }
 
        *info_out = info;
 
-       return success;
+       return task->success;
 }
 
 /* This function is called on the thread calling g_cancellable_cancel() */
@@ -382,8 +366,6 @@ static TrackerExtractTask *
 extract_task_new (TrackerExtract *extract,
                   const gchar    *uri,
                   const gchar    *mimetype,
-                  const gchar    *graph,
-                  const gchar    *urn,
                   GCancellable   *cancellable,
                   GAsyncResult   *res,
                   GError        **error)
@@ -423,8 +405,6 @@ extract_task_new (TrackerExtract *extract,
        task->res = (res) ? g_object_ref (res) : NULL;
        task->file = g_strdup (uri);
        task->mimetype = mimetype_used;
-       task->graph = g_strdup (graph);
-       task->urn = g_strdup (urn);
        task->extract = extract;
 
        if (task->cancellable) {
@@ -457,8 +437,6 @@ extract_task_free (TrackerExtractTask *task)
                tracker_mimetype_info_free (task->mimetype_handlers);
        }
 
-       g_free (task->urn);
-       g_free (task->graph);
        g_free (task->mimetype);
        g_free (task->file);
 
@@ -701,8 +679,6 @@ void
 tracker_extract_file (TrackerExtract      *extract,
                       const gchar         *file,
                       const gchar         *mimetype,
-                      const gchar         *graph,
-                      const gchar         *urn,
                       GCancellable        *cancellable,
                       GAsyncReadyCallback  cb,
                       gpointer             user_data)
@@ -723,8 +699,8 @@ tracker_extract_file (TrackerExtract      *extract,
 
        async_task = g_task_new (extract, cancellable, cb, user_data);
 
-       task = extract_task_new (extract, file, mimetype, graph, urn,
-                                cancellable, G_ASYNC_RESULT (async_task), &error);
+       task = extract_task_new (extract, file, mimetype, cancellable,
+                                G_ASYNC_RESULT (async_task), &error);
 
        if (error) {
                g_warning ("Could not get mimetype, %s", error->message);
@@ -764,7 +740,8 @@ tracker_extract_get_media_art_process (TrackerExtract *extract)
 void
 tracker_extract_get_metadata_by_cmdline (TrackerExtract *object,
                                          const gchar    *uri,
-                                         const gchar    *mime)
+                                         const gchar    *mime,
+                                         TrackerSerializationFormat  output_format)
 {
        GError *error = NULL;
        TrackerExtractPrivate *priv;
@@ -777,7 +754,7 @@ tracker_extract_get_metadata_by_cmdline (TrackerExtract *object,
 
        g_return_if_fail (uri != NULL);
 
-       task = extract_task_new (object, uri, mime, NULL, "_:file", NULL, NULL, &error);
+       task = extract_task_new (object, uri, mime, NULL, NULL, &error);
 
        if (error) {
                g_printerr ("%s, %s\n",
@@ -796,42 +773,44 @@ tracker_extract_get_metadata_by_cmdline (TrackerExtract *object,
        while (task->cur_func) {
                if (!filter_module (object, task->cur_module) &&
                    get_file_metadata (task, &info)) {
-                       const gchar *preupdate_str, *postupdate_str, *statements_str, *where;
-                       TrackerSparqlBuilder *builder;
+                       TrackerResource *resource = tracker_extract_info_get_resource (info);
+
+                       if (resource == NULL)
+                               break;
 
                        no_data_or_modules = FALSE;
-                       preupdate_str = statements_str = postupdate_str = NULL;
 
-                       builder = tracker_extract_info_get_metadata_builder (info);
+                       if (output_format == TRACKER_SERIALIZATION_FORMAT_SPARQL) {
+                               TrackerSparqlBuilder *builder;
+                               const char *text;
 
-                       if (tracker_sparql_builder_get_length (builder) > 0) {
-                               statements_str = tracker_sparql_builder_get_result (builder);
-                       }
+                               builder = tracker_sparql_builder_new_update ();
 
-                       builder = tracker_extract_info_get_preupdate_builder (info);
+                               /* If this was going into the tracker-store we'd generate a unique ID
+                                * here, so that the data persisted across file renames.
+                                */
+                               tracker_resource_set_identifier (resource, uri);
 
-                       if (tracker_sparql_builder_get_length (builder) > 0) {
-                               preupdate_str = tracker_sparql_builder_get_result (builder);
-                       }
+                               text = tracker_resource_print_sparql_update (resource, NULL, NULL);
 
-                       builder = tracker_extract_info_get_postupdate_builder (info);
+                               g_print ("%s\n", text);
 
-                       if (tracker_sparql_builder_get_length (builder) > 0) {
-                               postupdate_str = tracker_sparql_builder_get_result (builder);
-                       }
+                               g_free (text);
+                       } else if (output_format == TRACKER_SERIALIZATION_FORMAT_TURTLE) {
+                               char *turtle;
 
-                       where = tracker_extract_info_get_where_clause (info);
+                               /* If this was going into the tracker-store we'd generate a unique ID
+                                * here, so that the data persisted across file renames.
+                                */
+                               tracker_resource_set_identifier (resource, uri);
 
-                       g_print ("\n");
+                               turtle = tracker_resource_print_turtle (resource, NULL);
 
-                       g_print ("SPARQL pre-update:\n--\n%s--\n\n",
-                                preupdate_str ? preupdate_str : "");
-                       g_print ("SPARQL item:\n--\n%s--\n\n",
-                                statements_str ? statements_str : "");
-                       g_print ("SPARQL where clause:\n--\n%s--\n\n",
-                                where ? where : "");
-                       g_print ("SPARQL post-update:\n--\n%s--\n\n",
-                                postupdate_str ? postupdate_str : "");
+                               if (turtle) {
+                                       g_print ("%s\n", turtle);
+                                       g_free (turtle);
+                               }
+                       }
 
                        tracker_extract_info_unref (info);
                        break;
diff --git a/src/tracker-extract/tracker-extract.h b/src/tracker-extract/tracker-extract.h
index 704ece4..882c601 100644
--- a/src/tracker-extract/tracker-extract.h
+++ b/src/tracker-extract/tracker-extract.h
@@ -62,8 +62,6 @@ TrackerExtract *tracker_extract_new                     (gboolean
 void            tracker_extract_file                    (TrackerExtract         *extract,
                                                          const gchar            *file,
                                                          const gchar            *mimetype,
-                                                         const gchar            *graph,
-                                                         const gchar            *urn,
                                                          GCancellable           *cancellable,
                                                          GAsyncReadyCallback     cb,
                                                          gpointer                user_data);
@@ -81,9 +79,10 @@ void            tracker_extract_dbus_start              (TrackerExtract
 void            tracker_extract_dbus_stop               (TrackerExtract         *extract);
 
 /* Not DBus API */
-void            tracker_extract_get_metadata_by_cmdline (TrackerExtract         *object,
-                                                         const gchar            *path,
-                                                         const gchar            *mime);
+void            tracker_extract_get_metadata_by_cmdline (TrackerExtract             *object,
+                                                         const gchar                *path,
+                                                         const gchar                *mime,
+                                                         TrackerSerializationFormat  output_format);
 
 G_END_DECLS
 
diff --git a/src/tracker-extract/tracker-main.c b/src/tracker-extract/tracker-main.c
index 2c8ecd8..38b5f68 100644
--- a/src/tracker-extract/tracker-main.c
+++ b/src/tracker-extract/tracker-main.c
@@ -72,6 +72,7 @@ static gint verbosity = -1;
 static gchar *filename;
 static gchar *mime_type;
 static gchar *force_module;
+static gchar *output_format_name;
 static gboolean version;
 
 static TrackerConfig *config;
@@ -94,6 +95,9 @@ static GOptionEntry entries[] = {
          G_OPTION_ARG_STRING, &force_module,
          N_("Force a module to be used for extraction (e.g. \"foo\" for \"foo.so\")"),
          N_("MODULE") },
+       { "output-format", 'o', 0, G_OPTION_ARG_STRING, &output_format_name,
+         N_("Output results format: 'sparql', or 'turtle'"),
+         N_("FORMAT") },
        { "version", 'V', 0,
          G_OPTION_ARG_NONE, &version,
          N_("Displays version information"),
@@ -241,6 +245,9 @@ run_standalone (TrackerConfig *config)
        TrackerExtract *object;
        GFile *file;
        gchar *uri;
+       GEnumClass *enum_class;
+       GEnumValue *enum_value;
+       TrackerSerializationFormat output_format;
 
        /* Set log handler for library messages */
        g_log_set_default_handler (log_handler, NULL);
@@ -250,6 +257,20 @@ run_standalone (TrackerConfig *config)
                verbosity = 3;
        }
 
+       if (!output_format_name) {
+               output_format_name = "turtle";
+       }
+
+       /* Look up the output format by name */
+       enum_class = g_type_class_ref (TRACKER_TYPE_SERIALIZATION_FORMAT);
+       enum_value = g_enum_get_value_by_nick (enum_class, output_format_name);
+       g_type_class_unref (enum_class);
+       if (!enum_value) {
+               g_printerr (N_("Unsupported serialization format '%s'\n"), output_format_name);
+               return EXIT_FAILURE;
+       }
+       output_format = enum_value->value;
+
        tracker_locale_init ();
 
        /* This makes sure we don't steal all the system's resources */
@@ -268,7 +289,7 @@ run_standalone (TrackerConfig *config)
                return EXIT_FAILURE;
        }
 
-       tracker_extract_get_metadata_by_cmdline (object, uri, mime_type);
+       tracker_extract_get_metadata_by_cmdline (object, uri, mime_type, output_format);
 
        g_object_unref (object);
        g_object_unref (file);
diff --git a/src/tracker/tracker-extract.c b/src/tracker/tracker-extract.c
index d4979f3..fad25f4 100644
--- a/src/tracker/tracker-extract.c
+++ b/src/tracker/tracker-extract.c
@@ -31,6 +31,7 @@
 #include "tracker-extract.h"
 
 static gchar *verbosity;
+static gchar *output_format = "turtle";
 static gchar **filenames;
 
 #define EXTRACT_OPTIONS_ENABLED()        \
@@ -40,6 +41,9 @@ static GOptionEntry entries[] = {
        { "verbosity", 'v', 0, G_OPTION_ARG_STRING, &verbosity,
          N_("Sets the logging verbosity to LEVEL ('debug', 'detailed', 'minimal', 'errors') for all 
processes"),
          N_("LEVEL") },
+       { "output-format", 'o', 0, G_OPTION_ARG_STRING, &output_format,
+         N_("Output results format: 'sparql', or 'turtle'"),
+         N_("FORMAT") },
        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
          N_("FILE"),
          N_("FILE") },
@@ -48,7 +52,8 @@ static GOptionEntry entries[] = {
 
 
 static gint
-extract_files (TrackerVerbosity verbosity)
+extract_files (TrackerVerbosity  verbosity,
+               char             *output_format)
 {
        char **p;
        char *tracker_extract_path;
@@ -60,7 +65,10 @@ extract_files (TrackerVerbosity verbosity)
        tracker_extract_path = g_build_filename(LIBEXECDIR, "tracker-extract", NULL);
 
        for (p = filenames; *p; p++) {
-               char *argv[] = {tracker_extract_path, "--verbosity", verbosity_str, "--file", *p, NULL};
+               char *argv[] = {tracker_extract_path,
+                               "--output-format", output_format,
+                               "--verbosity", verbosity_str,
+                               "--file", *p, NULL };
 
                g_spawn_sync(NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, NULL, NULL, &error);
 
@@ -99,7 +107,7 @@ extract_run (void)
                }
        }
 
-       return extract_files (verbosity_level);
+       return extract_files (verbosity_level, output_format);
 }
 
 static int
diff --git a/tests/libtracker-extract/tracker-extract-info-test.c 
b/tests/libtracker-extract/tracker-extract-info-test.c
index d8b3b18..d189d44 100644
--- a/tests/libtracker-extract/tracker-extract-info-test.c
+++ b/tests/libtracker-extract/tracker-extract-info-test.c
@@ -29,21 +29,12 @@ test_extract_info_setters (void)
 
         file = g_file_new_for_path ("./imaginary-file-2");
 
-        info = tracker_extract_info_new (file, "imaginary/mime", "test-graph", "test-urn");
+        info = tracker_extract_info_new (file, "imaginary/mime");
         info_ref = tracker_extract_info_ref (info);
 
         g_assert (g_file_equal (file, tracker_extract_info_get_file (info)));
 
         g_assert_cmpstr (tracker_extract_info_get_mimetype (info), ==, "imaginary/mime");
-        g_assert_cmpstr (tracker_extract_info_get_graph (info), ==, "test-graph");
-        g_assert_cmpstr (tracker_extract_info_get_urn (info), ==, "test-urn");
-        g_assert (tracker_extract_info_get_preupdate_builder (info));
-        g_assert (tracker_extract_info_get_postupdate_builder (info));
-        g_assert (tracker_extract_info_get_metadata_builder (info));
-
-        g_assert (!tracker_extract_info_get_where_clause (info));
-        tracker_extract_info_set_where_clause (info, "where stuff");
-        g_assert_cmpstr (tracker_extract_info_get_where_clause (info), ==, "where stuff");
 
         tracker_extract_info_unref (info_ref);
         tracker_extract_info_unref (info);
@@ -59,7 +50,7 @@ test_extract_info_empty_objects (void)
 
         file = g_file_new_for_path ("./imaginary-file");
 
-        info = tracker_extract_info_new (file, "imaginary/mime", "test-graph", "test-urn");
+        info = tracker_extract_info_new (file, "imaginary/mime");
         info_ref = tracker_extract_info_ref (info);
 
         tracker_extract_info_unref (info_ref);
diff --git a/tests/libtracker-extract/tracker-test-xmp.c b/tests/libtracker-extract/tracker-test-xmp.c
index 0936e2c..0cf7afc 100644
--- a/tests/libtracker-extract/tracker-test-xmp.c
+++ b/tests/libtracker-extract/tracker-test-xmp.c
@@ -284,108 +284,53 @@ test_xmp_orientation (void)
 static void
 test_xmp_apply (void)
 {
-       TrackerSparqlBuilder *metadata, *preupdate;
-       GString *where;
+       TrackerResource *resource;
+       TrackerResource *artist;
        TrackerXmpData *data;
-       const gchar *graph = NULL;
 
-       metadata = tracker_sparql_builder_new_update ();
-       preupdate = tracker_sparql_builder_new_update ();
-       where = g_string_new ("");
+       resource = tracker_resource_new ("urn:uuid:test");
 
        data = tracker_xmp_new (EXAMPLE_XMP, strlen (EXAMPLE_XMP), "urn:uuid:test");
        g_assert (data != NULL);
 
-       tracker_sparql_builder_insert_open (metadata, NULL);
-       tracker_sparql_builder_subject_iri (metadata, "urn:uuid:test");
+       g_assert (tracker_xmp_apply_to_resource (resource, data));
 
-       g_assert (tracker_xmp_apply (preupdate, metadata, graph, where, "urn:uuid:test", data));
+       /* We just check a few of the properties at random. */
+       g_assert_cmpstr (tracker_resource_get_first_string (resource, "nie:description"), ==,
+                        "Description of the content");
 
-       tracker_sparql_builder_insert_close (metadata);
+       artist = tracker_resource_get_first_relation (resource, "nco:contributor");
+       g_assert_cmpstr (tracker_resource_get_first_string(artist, "nco:fullname"), ==,
+                        "Artist in exif");
 
-       /* This is the only way to check the sparql is kinda correct */
-
-       /* Disabled this for 0.8.5. It was reporting 41 not 50, this
-        * test is not credible and I can't see how it can be trusted
-        * as a method for making sure the query is correct.
-        *
-        * -mr
-        */
-
-       /* g_assert_cmpint (tracker_sparql_builder_get_length (metadata), ==, 50); */
-        g_string_free (where, TRUE);
-        g_object_unref (metadata);
-        g_object_unref (preupdate);
-
-        tracker_xmp_free (data);
+       tracker_xmp_free (data);
 }
 
 static void
 test_xmp_apply_location (void)
 {
        TrackerXmpData data = { 0, };
-       TrackerSparqlBuilder *metadata, *preupdate;
-       GString *where;
-       const gchar *graph = NULL;
+       TrackerResource *resource, *location, *address;
 
        data.address = g_strdup ("Itamerenkatu 11-13");
        data.city = g_strdup ("Helsinki");
        data.state = g_strdup ("N/A");
        data.country = g_strdup ("Findland");
 
-       metadata = tracker_sparql_builder_new_update ();
-       preupdate = tracker_sparql_builder_new_update ();
-       where = g_string_new ("");
-
-       tracker_sparql_builder_insert_open (metadata, NULL);
-       tracker_sparql_builder_subject_iri (metadata, "urn:uuid:test");
-
-       g_assert (tracker_xmp_apply (preupdate, metadata, graph, where, "urn:uuid:test", &data));
-
-       tracker_sparql_builder_insert_close (metadata);
+       resource = tracker_resource_new ("urn:uuid:test");
 
-       /* This is the only way to check the sparql is kinda correct */
+       g_assert (tracker_xmp_apply_to_resource (resource, &data));
 
-       /* The builder just contains this:
-          <urn:uuid:test> slo:location [ a slo:GeoLocation ;
-          slo:postalAddress <urn:uuid:c50c4305-c617-4188-b3d3-42ba2291d0de>] .
-          } */
+       location = tracker_resource_get_first_relation (resource, "slo:location");
+       address = tracker_resource_get_first_relation (location, "slo:postalAddress");
 
-       g_assert_cmpint (tracker_sparql_builder_get_length (metadata), >=, 3);
+       g_assert_cmpstr (tracker_resource_get_first_string (address, "nco:streetAddress"), ==, data.address);
+       g_assert_cmpstr (tracker_resource_get_first_string (address, "nco:region"), ==, data.state);
+       g_assert_cmpstr (tracker_resource_get_first_string (address, "nco:locality"), ==, data.city);
+       g_assert_cmpstr (tracker_resource_get_first_string (address, "nco:country"), ==, data.country);
 }
 
 
-/*
- * The generated sparql cannot be validated automatically.
- * Debug function to print it in the terminal.
- */
-static void
-debug_print_sparql (TrackerXmpData *data)
-{
-       /* To print the sparql */
-       TrackerSparqlBuilder *metadata, *preupdate;
-       GString *where;
-       const gchar *graph = NULL;
-
-       metadata = tracker_sparql_builder_new_update ();
-       preupdate = tracker_sparql_builder_new_update ();
-       where = g_string_new ("");
-
-       tracker_sparql_builder_insert_open (metadata, NULL);
-       tracker_sparql_builder_subject_iri (metadata, "urn:uuid:test");
-
-       tracker_xmp_apply (preupdate, metadata, graph, where, "urn:uuid:test", data);
-
-       tracker_sparql_builder_insert_close (metadata);
-
-       g_print ("%s\n", tracker_sparql_builder_get_result (preupdate));
-       g_print ("%s\n", tracker_sparql_builder_get_result (metadata));
-
-       g_object_unref (metadata);
-       g_object_unref (preupdate);
-       g_string_free (where, TRUE);
-}
-
 static void
 test_xmp_regions (void)
 {
@@ -426,10 +371,6 @@ test_xmp_regions (void)
        g_assert_cmpstr (region->type, ==, "Face");
        g_assert_cmpstr (region->title, ==, "John Doe");
 
-       if (0) {
-               debug_print_sparql (data);
-       }
-
        tracker_xmp_free (data);
 }
 
@@ -476,8 +417,6 @@ test_xmp_regions_quill (void)
        g_assert_cmpstr (region->link_class, ==, "nco:PersonContact");
        g_assert_cmpstr (region->link_uri, ==, "urn:uuid:1");
 
-       //debug_print_sparql (data);
-
        tracker_xmp_free (data);
 }
 
@@ -521,8 +460,6 @@ test_xmp_regions_ns_prefix (void)
        g_assert_cmpstr (region->type, ==, "Face");
        g_assert_cmpstr (region->title, ==, "Average Joe");
 
-       //debug_print_sparql (data);
-
        tracker_xmp_free (data);
 }
 
@@ -557,8 +494,6 @@ test_xmp_regions_nb282393 ()
        g_assert_cmpstr (region->height, ==, "0.440000");
        g_assert_cmpstr (region->title, ==, " ");
 
-       //debug_print_sparql (data);
-
        tracker_xmp_free (data);
 }
 
@@ -596,8 +531,6 @@ test_xmp_regions_nb282393_2 ()
         g_assert_cmpstr (region->link_class, ==, "nco:PersonContact");
         g_assert_cmpstr (region->link_uri, ==, "urn:uuid:840a3c05-6cc6-48a1-bb56-fc50fae3345a");
 
-       //debug_print_sparql (data);
-
        tracker_xmp_free (data);
 }
 


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