[gdome] Fix for XPath with default namespace



This fixes the issues mentioned before.

If your document uses a default namespace, that is, a namespace without a 
prefix, then you should register a default namespace with 
gdome_xpnsresolv_registerNs() and use this prefix with XPaths.

Tested with gdome-test-xpath-ns.c and did run against valgrind without leaks.

-- 
Gustavo Sverzut Barbieri
------------------------
Instituto Nokia de Tecnologia - INdT

Jabber: barbieri gmail com
   MSN: barbieri gmail com
  ICQ#: 17249123
 Skype: gsbarbieri
Mobile: +55 (81) 9927 0010
 Phone:  +1 (347) 624 6296; 08122692 sip stanaphone com
   GPG: 0xB640E1A2 @ wwwkeys.pgp.net
diff -x '*.a' -x '*.so' -x '*.o' -x CVS -x Makefile -ur gdome2/libgdome/gdome-xpath.c gdome2-fix/libgdome/gdome-xpath.c
--- gdome2/libgdome/gdome-xpath.c	2002-03-01 01:00:20.000000000 -0300
+++ gdome2-fix/libgdome/gdome-xpath.c	2006-03-31 17:22:36.000000000 -0300
@@ -204,6 +204,28 @@
 	*exc = 0;
 	return ((Gdome_xpath_XPathNSResolver *)self)->vtab->lookupNamespaceURI (self, prefix, exc);
 }
+/**
+ * gdome_xpnsresolv_registerNs:
+ * @self: GdomeXPathNSResolver Object ref
+ * @prefix: The prefix of the namespace to look for
+ * @uri: The URI to associate to the given namespace
+ * @exc: Exception Object ref
+ *
+ * Associate prefix with URI to use with this namespace resolver.
+ */
+void
+gdome_xpnsresolv_registerNs (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeDOMString *uri, GdomeException *exc)
+{
+	g_assert (exc != NULL);
+
+	if (self == NULL)
+		*exc = GDOME_NULL_POINTER_ERR;
+	else
+		*exc = GDOME_NOEXCEPTION_ERR;
+
+	((Gdome_xpath_XPathNSResolver *)self)->vtab->registerNs (self, prefix, uri, exc);
+}
+
 
 /******************************************************************************
           GdomeXPathResult interface API
diff -x '*.a' -x '*.so' -x '*.o' -x CVS -x Makefile -ur gdome2/libgdome/gdome-xpath.h gdome2-fix/libgdome/gdome-xpath.h
--- gdome2/libgdome/gdome-xpath.h	2002-03-01 01:00:20.000000000 -0300
+++ gdome2-fix/libgdome/gdome-xpath.h	2006-03-30 21:31:28.000000000 -0300
@@ -69,10 +69,13 @@
 GdomeXPathNSResolver * gdome_xpeval_createNSResolver (GdomeXPathEvaluator *self, GdomeNode *nodeResolver, GdomeException *exc);
 GdomeXPathResult * gdome_xpeval_createResult (GdomeXPathEvaluator *self, GdomeException *exc);
 GdomeXPathResult *gdome_xpeval_evaluate (GdomeXPathEvaluator *self, GdomeDOMString *expression, GdomeNode *contextNode, GdomeXPathNSResolver *resolver, unsigned int type, GdomeXPathResult *result, GdomeException *exc);
+
 GdomeXPathNSResolver * gdome_xpnsresolv_mkref( GdomeNode *nodeResolver );
 void gdome_xpnsresolv_ref (GdomeXPathNSResolver *self, GdomeException *exc);
 void gdome_xpnsresolv_unref (GdomeXPathNSResolver *self, GdomeException *exc);
 GdomeDOMString * gdome_xpnsresolv_lookupNamespaceURI( GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeException *exc);
+void gdome_xpnsresolv_registerNs (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeDOMString *uri, GdomeException *exc);
+
 void gdome_xpresult_ref (GdomeXPathResult *self, GdomeException *exc);
 void gdome_xpresult_unref (GdomeXPathResult *self, GdomeException *exc);
 unsigned short gdome_xpresult_resultType (GdomeXPathResult *self, GdomeException *exc);
diff -x '*.a' -x '*.so' -x '*.o' -x CVS -x Makefile -ur gdome2/libgdome/xpath/gdome-xpath-xpeval.c gdome2-fix/libgdome/xpath/gdome-xpath-xpeval.c
--- gdome2/libgdome/xpath/gdome-xpath-xpeval.c	2002-03-01 00:33:26.000000000 -0300
+++ gdome2-fix/libgdome/xpath/gdome-xpath-xpeval.c	2006-03-31 17:09:23.000000000 -0300
@@ -163,6 +163,7 @@
   xmlNodePtr refNode;
   xmlChar *path;
   Gdome_xml_Node *cn = (Gdome_xml_Node *)contextNode;
+	int free_namespaces = 1;
 	Gdome_xpath_XPathNSResolver *resolv = (Gdome_xpath_XPathNSResolver *)resolver;
 
   g_return_val_if_fail (expression != NULL, NULL);
@@ -178,13 +179,29 @@
 			while (ctxt->namespaces[ctxt->nsNr] != NULL)
 				ctxt->nsNr++;
 		}
+		if (resolv->nslist != NULL) {
+			if (ctxt->namespaces != NULL) {
+				int i = ctxt->nsNr;
+				ctxt->nsNr += resolv->nslist_size;
+				ctxt->namespaces = (xmlNsPtr *) xmlRealloc (ctxt->namespaces,
+																										(ctxt->nsNr + 1) *
+																										sizeof (xmlNsPtr));
+				memcpy (ctxt->namespaces + i, resolv->nslist,
+								resolv->nslist_size * sizeof (xmlNsPtr));
+				ctxt->namespaces[ctxt->nsNr] = NULL;
+			} else {
+ 				ctxt->namespaces = resolv->nslist;
+ 				free_namespaces = 0;
+				ctxt->nsNr = resolv->nslist_size;
+			}
+		}
 	}
 
   path = expression->str;
 	res = xmlXPathEval( path, ctxt );
 
 	/* XML::LibXML should also have this patch... */
-	if (ctxt->namespaces != NULL)
+	if ((ctxt->namespaces != NULL) && free_namespaces)
 		xmlFree(ctxt->namespaces);
 
 	xmlXPathFreeContext(ctxt);
diff -x '*.a' -x '*.so' -x '*.o' -x CVS -x Makefile -ur gdome2/libgdome/xpath/gdome-xpath-xpnsresolv.c gdome2-fix/libgdome/xpath/gdome-xpath-xpnsresolv.c
--- gdome2/libgdome/xpath/gdome-xpath-xpnsresolv.c	2002-03-01 00:33:46.000000000 -0300
+++ gdome2-fix/libgdome/xpath/gdome-xpath-xpnsresolv.c	2006-03-31 17:23:19.000000000 -0300
@@ -34,7 +34,8 @@
   {
 		gdome_xpath_xpnsresolv_ref,
 		gdome_xpath_xpnsresolv_unref,
-    gdome_xpath_xpnsresolv_lookupNamespaceURI
+		gdome_xpath_xpnsresolv_lookupNamespaceURI,
+		gdome_xpath_xpnsresolv_registerNs
   };
 
 GdomeXPathNSResolver *
@@ -48,6 +49,8 @@
   resolv->n = priv->n;
 	resolv->refcnt = 1;
 	resolv->gnode = nodeResolver;
+	resolv->nslist = NULL;
+	resolv->nslist_size = 0;
 	gdome_xml_n_ref ( nodeResolver, &exc);
   return (GdomeXPathNSResolver *)resolv;
 }
@@ -90,6 +93,17 @@
 	priv->refcnt--;
 
 	if (priv->refcnt == 0) {
+		if (priv->nslist) {
+			unsigned i;
+			xmlNsPtr ns = *priv->nslist;
+			for (i=0; i < priv->nslist_size; i++, ns++) {
+				xmlFree ((char*)ns->href);
+				xmlFree ((char*)ns->prefix);
+				xmlFree (ns);
+			}
+
+			xmlFree (priv->nslist);
+		}
 		gdome_xml_n_unref (priv->gnode, exc);
 		g_free (self);
 	}
@@ -119,3 +133,41 @@
     return NULL;
   }
 }
+
+/**
+ * gdome_xpath_xpnsresolv_registerNs:
+ * @self: GdomeXPathNSResolver Object ref
+ * @prefix: The prefix of the namespace to look for
+ * @uri: The URI to associate to the given namespace
+ * @exc: Exception Object ref
+ *
+ * Associate prefix with URI to use with this namespace resolver.
+ */
+void
+gdome_xpath_xpnsresolv_registerNs (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeDOMString *uri, GdomeException *exc)
+{
+  Gdome_xpath_XPathNSResolver *priv = (Gdome_xpath_XPathNSResolver *)self;
+	xmlNsPtr ns;
+
+	g_assert( exc != NULL );
+
+	if ((self == NULL) || (prefix == NULL) || (uri == NULL))
+		*exc = GDOME_NULL_POINTER_ERR;
+
+	if (priv->nslist == NULL) {
+		priv->nslist_size = 1;
+		priv->nslist = (xmlNsPtr *) xmlMalloc (2 * sizeof (xmlNsPtr));
+	} else {
+		priv->nslist_size ++;
+		priv->nslist = (xmlNsPtr *) xmlRealloc (priv->nslist,
+																						(priv->nslist_size + 1) *
+																						sizeof (xmlNsPtr));
+	}
+	ns = (xmlNsPtr) xmlMalloc (sizeof (xmlNs));
+	memset (ns, 0, sizeof(xmlNs));
+	ns->href = xmlStrdup (uri->str);
+	ns->prefix = xmlStrdup (prefix->str);
+
+	priv->nslist[priv->nslist_size - 1] = ns;
+	priv->nslist[priv->nslist_size] = NULL;
+}
diff -x '*.a' -x '*.so' -x '*.o' -x CVS -x Makefile -ur gdome2/libgdome/xpath/gdome-xpath-xpnsresolv.h gdome2-fix/libgdome/xpath/gdome-xpath-xpnsresolv.h
--- gdome2/libgdome/xpath/gdome-xpath-xpnsresolv.h	2005-12-03 06:29:18.000000000 -0300
+++ gdome2-fix/libgdome/xpath/gdome-xpath-xpnsresolv.h	2006-03-30 21:14:33.000000000 -0300
@@ -25,6 +25,7 @@
 	void (*ref) (GdomeXPathNSResolver *self, GdomeException *exc);
 	void (*unref) (GdomeXPathNSResolver *self, GdomeException *exc);
   GdomeDOMString *(*lookupNamespaceURI) (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeException *exc);
+	void (*registerNs) (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeDOMString *uri, GdomeException *exc);
 };
 
 typedef struct _Gdome_xpath_XPathNSResolver Gdome_xpath_XPathNSResolver;
@@ -35,12 +36,15 @@
 
 	GdomeNode *gnode;
 	xmlNodePtr n;
+	xmlNsPtr *nslist;
+	unsigned nslist_size;
 };
 
 GdomeXPathNSResolver * gdome_xpath_xpnsresolv_mkref( GdomeNode *nodeResolver );
 void gdome_xpath_xpnsresolv_ref (GdomeXPathNSResolver *self, GdomeException *exc);
 void gdome_xpath_xpnsresolv_unref (GdomeXPathNSResolver *self, GdomeException *exc);
 GdomeDOMString * gdome_xpath_xpnsresolv_lookupNamespaceURI( GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeException *exc);
+void gdome_xpath_xpnsresolv_registerNs (GdomeXPathNSResolver *self, GdomeDOMString *prefix, GdomeDOMString *uri, GdomeException *exc);
 
 extern const GdomeXPathNSResolverVtab gdome_xpath_xpnsresolv_vtab;
 
#include <gdome.h>
#include <gdome-xpath.h>
#include <stdio.h>
#include <string.h>

static char uri[] = "http://www.indt.org.br";;
static char xml[] = \
"<doc xmlns=\"http://www.indt.org.br\";>" \
"<a><b><p attr=\"name1\">value1.1</p><p attr=\"name2\">value1.2</p></b></a>" \
"<d><p attr=\"name1\">value2</p></d>" \
"</doc>";

GdomeXPathResult *
xpath_node( const char *expr, const char *prefix, const char *uri,
	    GdomeNode *context, GdomeException *exc )
{
  GdomeException clean_exc = GDOME_NOEXCEPTION_ERR;
  GdomeXPathResult *res = NULL;
  GdomeXPathEvaluator *eval = NULL;
  GdomeDOMString *s = NULL, *s_prefix = NULL, *s_uri = NULL;
  GdomeDocument *doc = NULL;
  GdomeElement *root = NULL;
  GdomeXPathNSResolver *nsresolv = NULL;

  if ( gdome_n_nodeType( context, exc ) == GDOME_DOCUMENT_NODE )
    {
      doc = (GdomeDocument*)context;
      gdome_doc_ref( doc, exc );
    }
  else
    doc = gdome_n_ownerDocument( context, exc );

  if ( *exc ) goto clean_up;

  root = gdome_doc_documentElement( doc, exc );
  if ( *exc ) goto clean_up;

  eval = gdome_xpeval_mkref();

  g_assert( eval );

  nsresolv = gdome_xpeval_createNSResolver( eval, (GdomeNode*)root, exc );
  if ( *exc ) goto clean_up;

  s_prefix = gdome_str_mkref( prefix );
  s_uri = gdome_str_mkref( uri );

  gdome_xpnsresolv_registerNs( nsresolv, s_prefix, s_uri, exc );
  if ( *exc ) goto clean_up;

  s = gdome_str_mkref( expr );

  g_assert( s );

  res = gdome_xpeval_evaluate( eval, s, context, nsresolv, 0, NULL, exc );
  if ( *exc ) goto clean_up;

 clean_up:
  if ( s )
    gdome_str_unref( s );

  if ( s_prefix )
    gdome_str_unref( s_prefix );

  if ( s_uri )
    gdome_str_unref( s_uri );

  if ( eval )
    gdome_xpeval_unref( eval, &clean_exc );

  if ( nsresolv )
    gdome_xpnsresolv_unref( nsresolv, &clean_exc );

  if ( root )
    gdome_el_unref( root, &clean_exc );

  if ( doc )
    gdome_doc_unref( doc, &clean_exc );

  return res;
}


GdomeXPathResult *
xpath_xml( const char *expr, const char *prefix, const char *uri,
	   char *xml, GdomeDocument *doc, GdomeException *exc )
{
  GdomeException clean_exc = GDOME_NOEXCEPTION_ERR;
  GdomeDOMImplementation *domimpl = NULL;
  GdomeXPathResult *res = NULL;

  domimpl = gdome_di_mkref();
  doc = gdome_di_createDocFromMemory( domimpl, xml, GDOME_LOAD_PARSING, exc );
  if ( *exc ) goto clean_up;

  res = xpath_node( expr, prefix, uri, (GdomeNode*)doc, exc );
  if ( *exc ) goto clean_up;

 clean_up:
  if ( domimpl )
    gdome_di_unref( domimpl, &clean_exc );

  return res;
}

int
test_root( void )
{
  GdomeException exc = GDOME_NOEXCEPTION_ERR;
  GdomeDocument *doc = NULL;
  GdomeXPathResult *res = xpath_xml( "/", "ns", uri, xml, doc,  &exc );
  GdomeNode *n = NULL;
  GdomeDOMString *s = NULL;
  unsigned i = 0;

  g_assert( res );

  while ( ( n = gdome_xpresult_iterateNext( res, &exc ) ) != NULL )
    {
      s = gdome_n_nodeName( n, &exc );
      if ( exc ) goto clean_up;

      g_assert( strcmp( "#document", s->str ) == 0 );

      gdome_str_unref( s );
      s = NULL;

      gdome_n_unref( n, &exc );
      if ( exc ) goto clean_up;
      n = NULL;

      i++;
    }

  g_assert( i == 1 );


 clean_up:
  if ( exc )
    fprintf( stderr, "Exception: %d\n", exc );

  if ( s )
    gdome_str_unref( s );

  if ( n )
    gdome_n_unref( n, &exc );

  if ( res )
    gdome_xpresult_unref( res, &exc );

  if ( doc )
    gdome_doc_unref( doc, &exc );

  return exc;
}


int
test_complete( void )
{
  GdomeException exc = GDOME_NOEXCEPTION_ERR;
  GdomeDocument *doc = NULL;
  GdomeXPathResult *res = xpath_xml( "//ns:a/ns:b/ns:p[ attr='name1']/text()",
				     "ns", uri, xml, doc,  &exc );
  GdomeNode *n = NULL;
  GdomeDOMString *s = NULL;
  unsigned i = 0;

  g_assert( res );

  while ( ( n = gdome_xpresult_iterateNext( res, &exc ) ) != NULL )
    {
      s = gdome_t_data( (GdomeText*)n, &exc );
      if ( exc ) goto clean_up;

      g_assert( strcmp( s->str, "value1.1" ) == 0 );

      gdome_str_unref( s );
      s = NULL;

      gdome_n_unref( n, &exc );
      if ( exc ) goto clean_up;
      n = NULL;

      i++;
    }

  g_assert( i == 1 );


 clean_up:
  if ( exc )
    fprintf( stderr, "Exception: %d\n", exc );

  if ( s )
    gdome_str_unref( s );

  if ( n )
    gdome_n_unref( n, &exc );

  if ( res )
    gdome_xpresult_unref( res, &exc );

  if ( doc )
    gdome_doc_unref( doc, &exc );

  return exc;
}


int
test_relative( void )
{
  GdomeException exc = GDOME_NOEXCEPTION_ERR;
  GdomeDocument *doc = NULL;
  GdomeXPathResult *res = NULL, *res2 = NULL;
  GdomeNode *n = NULL, *n2 = NULL;
  GdomeDOMString *s=NULL, *s2 = NULL;
  unsigned i = 0, j = 0;

  res = xpath_xml( "//ns:a/ns:b", "ns", uri, xml, doc,  &exc );
  if ( exc ) goto clean_up;

  g_assert( res );

  while ( ( n = gdome_xpresult_iterateNext( res, &exc ) ) != NULL )
    {
      s = gdome_n_nodeName( n, &exc );
      if ( exc ) goto clean_up;

      g_assert( strcmp( s->str, "b" ) == 0 );

      gdome_str_unref( s );
      s = NULL;

      res2 = xpath_node( "ns:p[ attr=\"name2\"]/text()", "ns", uri, n, &exc );
      if ( exc ) goto clean_up;

      g_assert( res2 );

      while ( ( n2 = gdome_xpresult_iterateNext( res2, &exc ) ) != NULL )
	{
	  s2 = gdome_t_data( (GdomeText*)n2, &exc );
	  if ( exc ) goto clean_up;

	  g_assert( strcmp( s2->str, "value1.2" ) == 0 );

	  gdome_str_unref( s2 );
	  s2 = NULL;

	  gdome_n_unref( n2, &exc );
	  if ( exc ) goto clean_up;
	  n2 = NULL;

	  j ++;
	}


      gdome_n_unref( n, &exc );
      if ( exc ) goto clean_up;
      n = NULL;

      i++;
    }

  g_assert( i == 1 );
  g_assert( j == 1 );


 clean_up:
  if ( exc )
    fprintf( stderr, "Exception: %d\n", exc );

  if ( s )
    gdome_str_unref( s );

  if ( s2 )
    gdome_str_unref( s2 );

  if ( n )
    gdome_n_unref( n, &exc );

  if ( n2 )
    gdome_n_unref( n2, &exc );

  if ( res )
    gdome_xpresult_unref( res, &exc );

  if ( res2 )
    gdome_xpresult_unref( res2, &exc );

  if ( doc )
    gdome_doc_unref( doc, &exc );

  return exc;
}


int
test_multiple( void )
{
  GdomeException exc = GDOME_NOEXCEPTION_ERR;
  GdomeDocument *doc = NULL;
  GdomeXPathResult *res = xpath_xml( "//ns:p[ attr=\"name1\"]/text()",
				     "ns", uri, xml, doc,  &exc );
  GdomeNode *n = NULL;
  GdomeDOMString *s = NULL;
  static const char *values[] = { "value1.1", "value2" };
  unsigned i = 0, max = 2;

  g_assert( res );

  while ( ( n = gdome_xpresult_iterateNext( res, &exc ) ) != NULL )
    {
      s = gdome_t_data( (GdomeText*)n, &exc );
      if ( exc ) goto clean_up;

      g_assert( i < max );

      g_assert( strcmp( s->str, values[ i ] ) == 0 );

      gdome_str_unref( s );
      s = NULL;

      gdome_n_unref( n, &exc );
      if ( exc ) goto clean_up;
      n = NULL;

      i++;
    }

  g_assert( i == 2 );


 clean_up:
  if ( exc )
    fprintf( stderr, "Exception: %d\n", exc );

  if ( s )
    gdome_str_unref( s );

  if ( n )
    gdome_n_unref( n, &exc );

  if ( res )
    gdome_xpresult_unref( res, &exc );

  if ( doc )
    gdome_doc_unref( doc, &exc );

  return exc;
}




int
main( int argc, char *argv[] )
{
  test_root();
  test_complete();
  test_relative();
  test_multiple();
  return 0;
}


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