示例#1
0
static GrlKeyID
register_metadata_key (GrlRegistry *registry,
                       GrlKeyID bind_key,
                       const char *name,
                       const char *nick,
                       const char *blurb)
{
  GParamSpec *spec;
  GrlKeyID key;

  spec = g_param_spec_string (name,
                              nick,
                              blurb,
                              NULL,
                              G_PARAM_READWRITE
                              | G_PARAM_STATIC_STRINGS);

  key = grl_registry_register_metadata_key (registry, spec, bind_key, NULL);

  if (key == GRL_METADATA_KEY_INVALID) {
    key = grl_registry_lookup_metadata_key (registry, name);
    if (grl_metadata_key_get_type (key) != G_TYPE_STRING) {
      key = GRL_METADATA_KEY_INVALID;
    }
  }

  return key;
}
static GrlKeyID
register_gravatar_key (GrlRegistry *registry,
                       const gchar *name,
                       const gchar *nick,
                       const gchar *blurb)
{
  GParamSpec *spec;
  GrlKeyID key;

  spec = g_param_spec_string (name,
                              nick,
                              blurb,
                              NULL,
                              G_PARAM_READWRITE);

  key = grl_registry_register_metadata_key (registry, spec, NULL);

  /* If key was not registered, could be that it is already registered. If so,
     check if type is the expected one, and reuse it */
  if (key == GRL_METADATA_KEY_INVALID) {
    key = grl_registry_lookup_metadata_key (registry, name);
    if (grl_metadata_key_get_type (key) != G_TYPE_STRING) {
      key = GRL_METADATA_KEY_INVALID;
    }
  }

  return key;
}
示例#3
0
/**
 * grl_related_keys_set_boxed:
 * @relkeys: set of related keys to modify
 * @key: key to change or add
 * @boxed: the new value
 *
 * Sets the value associated with @key into @relkeys. @key must have been
 * registered as a boxed-type key. Old value is freed and the new one is set.
 *
 * Since: 0.2.0
 */
void
grl_related_keys_set_boxed (GrlRelatedKeys *relkeys,
                            GrlKeyID key,
                            gconstpointer boxed)
{
  GValue value = { 0 };

  g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
  g_return_if_fail (boxed != NULL);

  g_value_init (&value, grl_metadata_key_get_type (key));
  g_value_set_boxed (&value, boxed);
  grl_related_keys_set (relkeys, key, &value);
  g_value_unset (&value);
}
示例#4
0
 static gboolean
 grl_bookmarks_plugin_init (GrlRegistry *registry,
                            GrlPlugin *plugin,
                            GList *configs)
 {
   GParamSpec *spec;
   GRL_LOG_DOMAIN_INIT (bookmarks_log_domain, "bookmarks");

   GRL_DEBUG ("grl_bookmarks_plugin_init");

   /* Initialize i18n */
   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");

   spec = g_param_spec_boxed ("bookmark-date",
                              "Bookmark date",
                              "When the media was bookmarked",
                              G_TYPE_DATE_TIME,
                              G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE),
   GRL_BOOKMARKS_KEY_BOOKMARK_TIME =
       grl_registry_register_metadata_key (registry, spec, NULL);
   /* If key was not registered, could be that it is already registered. If so,
      check if type is the expected one, and reuse it */
   if (GRL_BOOKMARKS_KEY_BOOKMARK_TIME == GRL_METADATA_KEY_INVALID) {
     g_param_spec_unref (spec);
     GRL_BOOKMARKS_KEY_BOOKMARK_TIME =
         grl_registry_lookup_metadata_key (registry, "bookmark-date");
     if (grl_metadata_key_get_type (GRL_BOOKMARKS_KEY_BOOKMARK_TIME)
         != G_TYPE_DATE_TIME) {
       GRL_BOOKMARKS_KEY_BOOKMARK_TIME = GRL_METADATA_KEY_INVALID;
     }
   }

   GrlBookmarksSource *source = grl_bookmarks_source_new ();
   grl_registry_register_source (registry,
                                 plugin,
                                 GRL_SOURCE (source),
                                 NULL);
   return TRUE;
 }
示例#5
0
void
mex_grilo_set_media_content_metadata (GrlMedia           *media,
                                      MexContentMetadata  mex_key,
                                      const gchar        *value)
{
  int      ival;
  float    fval;
  GrlKeyID grl_key;

  g_return_if_fail (GRL_IS_MEDIA (media));
  g_return_if_fail (mex_key < MEX_CONTENT_METADATA_LAST_ID);

  grl_key = _get_grl_key_from_mex (mex_key);

  if (!grl_key) {
    g_warning ("No grilo key to handle %s",
               mex_content_metadata_key_to_string (mex_key));
    return;
  }

  switch (grl_metadata_key_get_type (grl_key)) {
  case G_TYPE_STRING:
    grl_data_set_string (GRL_DATA (media), grl_key, value);
    break;

  case G_TYPE_INT:
    ival = atoi (value);
    grl_data_set_int (GRL_DATA (media), grl_key, ival);
    break;

  case G_TYPE_FLOAT:
    fval = atof (value);
    grl_data_set_float (GRL_DATA (media), grl_key, fval);
    break;
  }
}
static void
proxy_call_browse_grlnet_async_cb (GObject *source_object,
                                   GAsyncResult *res,
                                   gpointer user_data)
{
  RaitvOperation    *op = (RaitvOperation *) user_data;
  xmlDocPtr           doc = NULL;
  xmlXPathContextPtr  xpath = NULL;
  xmlXPathObjectPtr   obj = NULL;
  gint i, nb_items = 0;
  gsize length;


  GRL_DEBUG ("Response id=%u", op->operation_id);

  GError *wc_error = NULL;
  GError *error = NULL;
  gchar *content = NULL;

  if (g_cancellable_is_cancelled (op->cancellable)) {
    goto finalize;
  }


  if (!grl_net_wc_request_finish (GRL_NET_WC (source_object),
                                  res,
                                  &content,
                                  &length,
                                  &wc_error)) {
    error = g_error_new (GRL_CORE_ERROR,
                         GRL_CORE_ERROR_SEARCH_FAILED,
                         _("Failed to browse: %s"),
                         wc_error->message);

    op->callback (op->source,
                  op->operation_id,
                  NULL,
                  0,
                  op->user_data,
                  error);

    g_error_free (wc_error);
    g_error_free (error);

    return;
  }

  doc = xmlRecoverMemory (content, (gint) length);

  if (!doc) {
    GRL_DEBUG ("Doc failed");
    goto finalize;
  }

  xpath = xmlXPathNewContext (doc);
  if (!xpath) {
    GRL_DEBUG ("Xpath failed");
    goto finalize;
  }

  gchar* xquery=NULL;
  switch (classify_media_id (op->container_id))
    {
    case RAITV_MEDIA_TYPE_POPULAR_THEME:
      xquery = "/CLASSIFICAVISTI/content";
      break;
    case RAITV_MEDIA_TYPE_RECENT_THEME:
      xquery = "/INFORMAZIONICONTENTS/content";
      break;
    default:
      goto finalize;
    }

  obj = xmlXPathEvalExpression ((xmlChar *) xquery, xpath);
  if (obj)
    {
      nb_items = xmlXPathNodeSetGetLength (obj->nodesetval);
      xmlXPathFreeObject (obj);
    }

  if (nb_items < op->count)
    op->count = nb_items;

  op->category_info->count = nb_items;

  for (i = 0; i < nb_items; i++)
    {

      //Skip
      if(op->skip>0) {
        op->skip--;
        continue;
      }

      GrlRaitvSource *source = GRL_RAITV_SOURCE (op->source);
      GList *mapping = source->priv->raitv_browse_mappings;
      GrlMedia *media = grl_media_video_new ();

      while (mapping)
        {
          gchar *str;
          gchar *strvalue;

          RaitvAssoc *assoc = (RaitvAssoc *) mapping->data;
          str = g_strdup_printf ("string(%s[%i]/%s)",
                                 xquery,i + 1, assoc->exp);


          obj = xmlXPathEvalExpression ((xmlChar *) str, xpath);
          if (obj)
            {
              if (obj->stringval && obj->stringval[0] != '\0')
                {
                  strvalue = 	g_strdup((gchar *) obj->stringval);
                  //Sometimes GRL_METADATA_KEY_THUMBNAIL doesn't report complete url
                  if(assoc->grl_key == GRL_METADATA_KEY_THUMBNAIL && !g_str_has_prefix(strvalue,"http://www.rai.tv/")) {
                    strvalue = g_strdup_printf("http://www.rai.tv%s",obj->stringval);
                  }

                  GType _type;
                  _type = grl_metadata_key_get_type (assoc->grl_key);
                  switch (_type)
                    {
                    case G_TYPE_STRING:
                      grl_data_set_string (GRL_DATA (media),
                                           assoc->grl_key,
                                           strvalue);
                      break;

                    case G_TYPE_INT:
                      grl_data_set_int (GRL_DATA (media),
                                        assoc->grl_key,
                                        (gint) atoi (strvalue));
                      break;

                    case G_TYPE_FLOAT:
                      grl_data_set_float (GRL_DATA (media),
                                          assoc->grl_key,
                                          (gfloat) atof (strvalue));
                      break;

                    default:
                      /* G_TYPE_DATE_TIME is not a constant, so this has to be
                       * in "default:" */
                      if (_type == G_TYPE_DATE_TIME) {
                        int year,month,day,hour,minute,seconds;
                        sscanf((const char*)obj->stringval, "%02d/%02d/%04d %02d:%02d:%02d",
                               &day, &month, &year, &hour,&minute, &seconds);
                        GDateTime *date = g_date_time_new_local (year, month, day, hour,minute, seconds);
                        grl_data_set_boxed (GRL_DATA (media),
                                            assoc->grl_key, date);
                        if(date) g_date_time_unref (date);
                      } else {
                        GRL_DEBUG ("\tUnexpected data type: %s",
                                   g_type_name (_type));
                      }
                      break;
                    }
                  g_free (strvalue);
                }
              xmlXPathFreeObject (obj);
            }

          g_free (str);

          mapping = mapping->next;
        }

      op->callback (op->source,
                    op->operation_id,
                    media,
                    --op->count,
                    op->user_data,
                    NULL);

      if (op->count == 0) {
        break;
      }
    }

 finalize:
  g_clear_pointer (&xpath, xmlXPathFreeContext);
  g_clear_pointer (&doc, xmlFreeDoc);

  /* Signal the last element if it was not already signaled */
  if (nb_items == 0) {
    op->callback (op->source,
                  op->operation_id,
                  NULL,
                  0,
                  op->user_data,
                  NULL);
  }
  else {
    //Continue the search
    if(op->count>0) {
      //Skip the ones already read
      op->skip +=  nb_items;
      op->offset +=  nb_items;
      switch (classify_media_id (op->container_id))
		  {
        case RAITV_MEDIA_TYPE_POPULAR_THEME:
          produce_from_popular_theme(op);
          break;
        case RAITV_MEDIA_TYPE_RECENT_THEME:
          produce_from_recent_theme(op);
          break;
        default:
          g_assert_not_reached ();
          break;
		  }

    }
  }

}
static void
proxy_call_search_grlnet_async_cb (GObject *source_object,
                                   GAsyncResult *res,
                                   gpointer user_data)
{
  RaitvOperation    *op = (RaitvOperation *) user_data;
  xmlDocPtr           doc = NULL;
  xmlXPathContextPtr  xpath = NULL;
  xmlXPathObjectPtr   obj = NULL;
  gint i, nb_items = 0;
  gsize length;

  GRL_DEBUG ("Response id=%u", op->operation_id);

  GError *wc_error = NULL;
  GError *error = NULL;
  gchar *content = NULL;
  gboolean g_bVideoNotFound = TRUE;

  if (g_cancellable_is_cancelled (op->cancellable)) {
    goto finalize;
  }

  if (!grl_net_wc_request_finish (GRL_NET_WC (source_object),
                                  res,
                                  &content,
                                  &length,
                                  &wc_error)) {
    error = g_error_new (GRL_CORE_ERROR,
                         GRL_CORE_ERROR_SEARCH_FAILED,
                         _("Failed to search: %s"),
                         wc_error->message);

    op->callback (op->source,
                  op->operation_id,
                  NULL,
                  0,
                  op->user_data,
                  error);

   g_error_free (wc_error);
    g_error_free (error);

    return;
  }

  doc = xmlParseMemory (content, (gint) length);

  if (!doc) {
    GRL_DEBUG ("Doc failed");
    goto finalize;
  }

  xpath = xmlXPathNewContext (doc);
  if (!xpath) {
    GRL_DEBUG ("Xpath failed");
    goto finalize;
  }
  obj = xmlXPathEvalExpression ((xmlChar *) "/GSP/RES/R", xpath);
  if (obj)
    {
      nb_items = xmlXPathNodeSetGetLength (obj->nodesetval);
      xmlXPathFreeObject (obj);
    }

  for (i = 0; i < nb_items; i++)
    {
      //Search only videos
      gchar *str;
      str = g_strdup_printf ("string(/GSP/RES/R[%i]/MT[@N='videourl']/@V)",
                             i + 1);
      obj = xmlXPathEvalExpression ((xmlChar *) str, xpath);
      if (obj->stringval && obj->stringval[0] == '\0')
        continue;
      if(op->skip>0) {
        op->skip--;
        continue;
      }

      GrlRaitvSource *source = GRL_RAITV_SOURCE (op->source);
      GList *mapping = source->priv->raitv_search_mappings;
      GrlMedia *media = grl_media_video_new ();
      g_bVideoNotFound = FALSE;
      GRL_DEBUG ("Mappings count: %d",g_list_length(mapping));
      while (mapping)
        {
          RaitvAssoc *assoc = (RaitvAssoc *) mapping->data;
          str = g_strdup_printf ("string(/GSP/RES/R[%i]/%s)",
                                 i + 1, assoc->exp);

          GRL_DEBUG ("Xquery %s", str);
          gchar *strvalue;

          obj = xmlXPathEvalExpression ((xmlChar *) str, xpath);
          if (obj)
            {
              if (obj->stringval && obj->stringval[0] != '\0')
                {
                  strvalue = 	g_strdup((gchar *) obj->stringval);
                  //Sometimes GRL_METADATA_KEY_THUMBNAIL doesn't report complete url
                  if(assoc->grl_key == GRL_METADATA_KEY_THUMBNAIL && !g_str_has_prefix(strvalue,"http://www.rai.tv")) {
                    strvalue = g_strdup_printf("http://www.rai.tv%s",obj->stringval);
                  }

                  GType _type;
                  GRL_DEBUG ("\t%s -> %s", str, obj->stringval);
                  _type = grl_metadata_key_get_type (assoc->grl_key);
                  switch (_type)
                    {
                    case G_TYPE_STRING:
                      grl_data_set_string (GRL_DATA (media),
                                           assoc->grl_key,
                                           strvalue);
                      break;

                    case G_TYPE_INT:
                      grl_data_set_int (GRL_DATA (media),
                                        assoc->grl_key,
                                        (gint) atoi (strvalue));
                      break;

                    case G_TYPE_FLOAT:
                      grl_data_set_float (GRL_DATA (media),
                                          assoc->grl_key,
                                          (gfloat) atof (strvalue));
                      break;

                    default:
                      /* G_TYPE_DATE_TIME is not a constant, so this has to be
                       * in "default:" */
                      if (_type == G_TYPE_DATE_TIME) {
                        int year,month,day;
                        sscanf((const char*)obj->stringval, "%02d/%02d/%04d", &day, &month, &year);
                        GDateTime *date = g_date_time_new_local (year, month, day, 0, 0, 0);
                        GRL_DEBUG ("Setting %s to %s",
                                   grl_metadata_key_get_name (assoc->grl_key),
                                   g_date_time_format (date, "%F %H:%M:%S"));
                        grl_data_set_boxed (GRL_DATA (media),
                                            assoc->grl_key, date);
                        if(date) g_date_time_unref (date);
                      } else {
                        GRL_DEBUG ("\tUnexpected data type: %s",
                                   g_type_name (_type));
                      }
                      break;
                    }
                  g_free (strvalue);
                }
              xmlXPathFreeObject (obj);
            }

          g_free (str);

          mapping = mapping->next;
        }

      op->callback (op->source,
                    op->operation_id,
                    media,
                    --op->count,
                    op->user_data,
                    NULL);

      if (op->count == 0)
        break;
    }

 finalize:
  g_clear_pointer (&xpath, xmlXPathFreeContext);
  g_clear_pointer (&doc, xmlFreeDoc);

  /* Signal the last element if it was not already signaled */
  if (nb_items == 0 || g_bVideoNotFound) {
    op->callback (op->source,
                  op->operation_id,
                  NULL,
                  0,
                  op->user_data,
                  NULL);
  }
  else {
    //Continue the search
    if(op->count>0) {
		op->offset +=  nb_items;
		g_raitv_videos_search(op);
    }
  }

}
示例#8
0
static void
set_metadata_from_media (MexContent          *content,
                         GrlMedia            *media,
                         MexContentMetadata   mex_key)
{
  gchar       *string;
  const gchar *cstring;
  GrlKeyID     grl_key = _get_grl_key_from_mex (mex_key);
  gint n;
  gint year = 0;

  if (!grl_key)
    return;

  switch (grl_metadata_key_get_type (grl_key)) {
  case G_TYPE_STRING:
    cstring = grl_data_get_string (GRL_DATA (media), grl_key);

    if (cstring)
      {
        if (mex_key == MEX_CONTENT_METADATA_TITLE)
          {
            gchar *showname = NULL, *title, *season_str;
            gint season, episode;
            gchar *replacement;
            const gchar *mimetype;

            mimetype = mex_content_get_metadata (content,
                                                 MEX_CONTENT_METADATA_MIMETYPE);

            if (!mimetype)
              mimetype = "";

            if (g_str_has_prefix (mimetype, "video/"))
              {
                mex_metadata_from_uri (cstring, &title, &showname, &year,
                                       &season, &episode);
              }

            if (showname)
              {
                replacement = g_strdup_printf (_("Episode %d"), episode);
              }
            else
              {
                GRegex *regex;

                /* strip off any file extensions */
                regex = g_regex_new ("\\.....?$", 0, 0, NULL);
                replacement = g_regex_replace (regex, cstring, -1, 0, "", 0, NULL);

                g_regex_unref (regex);
              }

            if (!replacement)
              replacement = g_strdup (cstring);

            mex_content_set_metadata (content, mex_key, replacement);
            mex_content_set_metadata (content, MEX_CONTENT_METADATA_SERIES_NAME,
                                      showname);
            season_str = g_strdup_printf (_("Season %d"), season);
            mex_content_set_metadata (content, MEX_CONTENT_METADATA_SEASON,
                                      season_str);
            g_free (season_str);

            if (year)
              {
                replacement = g_strdup_printf ("%d", year);
                mex_content_set_metadata (content, MEX_CONTENT_METADATA_YEAR,
                                          replacement);

                g_free (replacement);
              }
          }
        else
          mex_content_set_metadata (content, mex_key, cstring);
      }
    break;

  case G_TYPE_INT:
    n = grl_data_get_int (GRL_DATA (media), grl_key);

    string = g_strdup_printf ("%i", n);
    mex_content_set_metadata (content, mex_key, string);
    g_free (string);
    break;

  case G_TYPE_FLOAT:
    string = g_strdup_printf ("%f", grl_data_get_float (GRL_DATA (media),
                                                        grl_key));
    mex_content_set_metadata (content, mex_key, string);
    g_free (string);
    break;
  }
}
示例#9
0
static void
call_raw_async_cb (GObject *     source_object,
                   GAsyncResult *res,
                   gpointer      data)
{
  BliptvOperation    *op = (BliptvOperation *) data;
  xmlDocPtr           doc = NULL;
  xmlXPathContextPtr  xpath = NULL;
  xmlXPathObjectPtr   obj = NULL;
  gint i, nb_items = 0;
  gchar *content = NULL;
  gchar *url;
  gsize length;

  GRL_DEBUG ("Response id=%u", op->operation_id);

  if (g_cancellable_is_cancelled (op->cancellable)) {
    goto finalize_send_last;
  }

  if (!grl_net_wc_request_finish (GRL_NET_WC (source_object),
                                  res,
                                  &content,
                                  &length,
                                  NULL)) {
    goto finalize_send_last;
  }

  doc = xmlParseMemory (content, (gint) length);

  if (!doc)
    goto finalize_send_last;

  xpath = xmlXPathNewContext (doc);
  if (!xpath)
    goto finalize_send_last;

  xmlXPathRegisterNs (xpath,
                      (xmlChar *) "blip",
                      (xmlChar *) BLIPTV_BACKEND "/dtd/blip/1.0");
  xmlXPathRegisterNs (xpath,
                      (xmlChar *) "media",
                      (xmlChar *) "http://search.yahoo.com/mrss/");

  obj = xmlXPathEvalExpression ((xmlChar *) "/rss/channel/item", xpath);
  if (obj)
    {
      nb_items = xmlXPathNodeSetGetLength (obj->nodesetval);
      xmlXPathFreeObject (obj);
    }

  if (nb_items == 0) {
    goto finalize_send_last;
  }

  /* Special case: when there are no results in a search, Blip.tv returns an
     element telling precisely that, no results found; so we need to report no
     results too */
  if (nb_items == 1) {
    obj = xmlXPathEvalExpression ((xmlChar *) "string(/rss/channel/item[0]/blip:item_id)", xpath);
    if (!obj || !obj->stringval || obj->stringval[0] == '\0') {
      g_clear_pointer (&obj, (GDestroyNotify) xmlXPathFreeObject);
      nb_items = 0;
      goto finalize_send_last;
    } else {
      xmlXPathFreeObject (obj);
    }
  }

  for (i = op->skip; i < nb_items; i++)
    {
      GList *mapping = bliptv_mappings;
      GrlMedia *media = grl_media_video_new ();

      while (mapping)
        {
          BliptvAssoc *assoc = (BliptvAssoc *) mapping->data;
          gchar *str;

          str = g_strdup_printf ("string(/rss/channel/item[%i]/%s)",
                                 i + 1, assoc->exp);

          obj = xmlXPathEvalExpression ((xmlChar *) str, xpath);
          if (obj)
            {
              if (obj->stringval && obj->stringval[0] != '\0')
                {
                  GType _type;
                  GRL_DEBUG ("\t%s -> %s", str, obj->stringval);
                  _type = grl_metadata_key_get_type (assoc->grl_key);
                  switch (_type)
                    {
                    case G_TYPE_STRING:
                      grl_data_set_string (GRL_DATA (media),
                                           assoc->grl_key,
                                           (gchar *) obj->stringval);
                      break;

                    case G_TYPE_INT:
                      grl_data_set_int (GRL_DATA (media),
                                        assoc->grl_key,
                                        (gint) atoi ((gchar *) obj->stringval));
                      break;

                    case G_TYPE_FLOAT:
                      grl_data_set_float (GRL_DATA (media),
                                          assoc->grl_key,
                                          (gfloat) atof ((gchar *) obj->stringval));
                      break;

                    default:
                      /* G_TYPE_DATE_TIME is not a constant, so this has to be
                       * in "default:" */
                      if (_type == G_TYPE_DATE_TIME) {
                        GDateTime *date =
                            grl_date_time_from_iso8601 ((gchar *) obj->stringval);
                        GRL_DEBUG ("Setting %s to %s",
                                   grl_metadata_key_get_name (assoc->grl_key),
                                   g_date_time_format (date, "%F %H:%M:%S"));
                        grl_data_set_boxed (GRL_DATA (media),
                                            assoc->grl_key, date);
                        g_date_time_unref (date);
                      } else {
                        GRL_DEBUG ("\tUnexpected data type: %s",
                                   g_type_name (_type));
                      }
                      break;
                    }
                }
              xmlXPathFreeObject (obj);
            }

          g_free (str);

          mapping = mapping->next;
        }

      op->callback (op->source,
                    op->operation_id,
                    media,
                    --op->count,
                    op->user_data,
                    NULL);

      if (op->count == 0)
        break;
    }

  if (op->count > 0) {
    /* Request next page */
    op->skip = 0;
    url = g_strdup_printf (op->url, ++op->page);

    GRL_DEBUG ("Operation %d: requesting page %d",
               op->operation_id,
               op->page);

    grl_net_wc_request_async (GRL_BLIPTV_SOURCE (op->source)->priv->wc,
                              url,
                              op->cancellable,
                              call_raw_async_cb,
                              op);
    g_free (url);

    goto finalize_free;
  }

 finalize_send_last:
  /* Signal the last element if it was not already signaled */
  if (nb_items == 0) {
    op->callback (op->source,
                  op->operation_id,
                  NULL,
                  0,
                  op->user_data,
                  NULL);
  }

 finalize_free:
  g_clear_pointer (&xpath, (GDestroyNotify) xmlXPathFreeContext);
  g_clear_pointer (&doc, (GDestroyNotify) xmlFreeDoc);
}