Index: ext/libxml/ruby_xml_document.c =================================================================== --- ext/libxml/ruby_xml_document.c (revision 524) +++ ext/libxml/ruby_xml_document.c (working copy) @@ -403,9 +403,19 @@ return(Qnil); } +void +ruby_xml_document_free(ruby_xml_document_t *rxd) { + /* clear direct ruby binding to the object */ + rxd->doc->_private = NULL; + if(rxd->ref_count > 1) { + rxd->ref_count--; + } else { + ruby_xml_document_release(rxd); + } +} void -ruby_xml_document_free(ruby_xml_document_t *rxd) { +ruby_xml_document_release(ruby_xml_document_t *rxd) { void *data; if (rxd->doc == NULL) return; @@ -524,6 +534,7 @@ xdoc->_private=(void*)obj; rx->data = NULL; rx->data_type = RUBY_LIBXML_SRC_TYPE_NULL; + rx->ref_count = 1; #ifdef NODE_DEBUG fprintf(stderr,"wrap rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)xnode,(long)obj); Index: ext/libxml/ruby_xml_xpath_object.h =================================================================== --- ext/libxml/ruby_xml_xpath_object.h (revision 524) +++ ext/libxml/ruby_xml_xpath_object.h (working copy) @@ -10,7 +10,7 @@ } ruby_xml_xpath_object; void ruby_init_xml_xpath_object(void); -VALUE ruby_xml_xpath_object_wrap(xmlXPathObjectPtr xpop); +VALUE ruby_xml_xpath_object_wrap(xmlXPathObjectPtr xpop, VALUE ctxt); VALUE ruby_xml_xpath_object_first(VALUE self); VALUE ruby_xml_xpath_object_to_a(VALUE self); Index: ext/libxml/ruby_xml_document.h =================================================================== --- ext/libxml/ruby_xml_document.h (revision 524) +++ ext/libxml/ruby_xml_document.h (working copy) @@ -11,11 +11,13 @@ xmlDocPtr doc; /* Tree/DOM interface */ int data_type; /* The data type referenced by *data */ void *data; /* Pointer to an external structure of options */ + int ref_count; } ruby_xml_document_t; VALUE ruby_xml_document_filename_get(VALUE self); VALUE ruby_xml_document_new_native(VALUE class, VALUE xmlver); void ruby_xml_document_free(ruby_xml_document_t *rxd); +void ruby_xml_document_release(ruby_xml_document_t *rxd); VALUE ruby_xml_document_root_get(VALUE self); void ruby_init_xml_document(void); Index: ext/libxml/ruby_xml_xpath_context.c =================================================================== --- ext/libxml/ruby_xml_xpath_context.c (revision 524) +++ ext/libxml/ruby_xml_xpath_context.c (working copy) @@ -28,11 +28,18 @@ xmlXPathFreeContext(ctxt); } +void +ruby_xml_xpath_context_mark(xmlXPathContextPtr ctxt) { + if(ctxt->doc != NULL && ctxt->doc->_private != NULL) { + rb_gc_mark((VALUE)ctxt->doc->_private); + } +} + VALUE ruby_xml_xpath_context_alloc(VALUE klass) { return Data_Wrap_Struct(cXMLXPathContext, - NULL, + ruby_xml_xpath_context_mark, ruby_xml_xpath_context_free, NULL); } @@ -75,7 +82,7 @@ DATA_PTR(self) = xmlXPathNewContext(rxd->doc); /* Save the doc as an attribute, this will expose it to Ruby's GC. */ - rb_iv_set(self, "@doc", document); + // rb_iv_set(self, "@doc", document); return self; } @@ -256,8 +263,8 @@ rb_raise(eXMLXPathInvalidPath, "Invalid XPath expression (expr could not be evaluated)"); - result = ruby_xml_xpath_object_wrap(xobject); - rb_iv_set(result, "@context", self); + result = ruby_xml_xpath_object_wrap(xobject, self); + //rb_iv_set(result, "@context", self); return result; } Index: ext/libxml/ruby_xml_xpointer.c =================================================================== --- ext/libxml/ruby_xml_xpointer.c (revision 524) +++ ext/libxml/ruby_xml_xpointer.c (working copy) @@ -5,6 +5,9 @@ #include "ruby_libxml.h" #include "ruby_xml_xpointer.h" +#undef LIBXML_XPTR_ENABLED + + VALUE cXMLXPointer; VALUE eXMLXPointerInvalidExpression; @@ -33,7 +36,7 @@ if (!xpop) rb_raise(eXMLXPointerInvalidExpression, "Invalid xpointer expression"); - result = ruby_xml_xpath_object_wrap(xpop); + result = ruby_xml_xpath_object_wrap(xpop, context); rb_iv_set(result, "@context", context); return(result); Index: ext/libxml/version.h =================================================================== --- ext/libxml/version.h (revision 524) +++ ext/libxml/version.h (working copy) @@ -5,5 +5,5 @@ #define RUBY_LIBXML_VERNUM 0 #define RUBY_LIBXML_VER_MAJ 0 #define RUBY_LIBXML_VER_MIN 8 -#define RUBY_LIBXML_VER_MIC 3 +#define RUBY_LIBXML_VER_MIC 3 #define RUBY_LIBXML_VER_PATCH 0 Index: ext/libxml/ruby_xml_attr.c =================================================================== --- ext/libxml/ruby_xml_attr.c (revision 524) +++ ext/libxml/ruby_xml_attr.c (working copy) @@ -30,7 +30,7 @@ xattr->_private=NULL; if (xattr->parent == NULL && xattr->doc == NULL ) { #ifdef NODE_DEBUG - fprintf(stderr,"ruby_xfree rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)rxn->node,(long)rxn->node->_private); + // fprintf(stderr,"ruby_xfree rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)rxn->node,(long)rxn->node->_private); #endif xmlFreeProp(xattr); } @@ -66,7 +66,7 @@ xattr->_private=(void*)result; #ifdef NODE_DEBUG - fprintf(stderr,"wrap rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)xnode,(long)obj); + // fprintf(stderr,"wrap rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)xnode,(long)obj); #endif return result; } Index: ext/libxml/ruby_xml_xpath_object.c =================================================================== --- ext/libxml/ruby_xml_xpath_object.c (revision 524) +++ ext/libxml/ruby_xml_xpath_object.c (working copy) @@ -49,19 +49,37 @@ void ruby_xml_xpath_object_free(xmlXPathObjectPtr xpop) { + ruby_xml_document_t* doc_struct = (ruby_xml_document_t*)xpop->user2; + doc_struct->ref_count--; + xmlXPathFreeObject(xpop); + + if(doc_struct->ref_count < 1) { + ruby_xml_document_release(doc_struct); + } } VALUE -ruby_xml_xpath_object_wrap(xmlXPathObjectPtr xpop) +ruby_xml_xpath_object_wrap(xmlXPathObjectPtr xpop, VALUE ctxt) { VALUE rval; + xmlXPathContextPtr xctxt; + xmlDocPtr doc; + VALUE doc_val; + ruby_xml_document_t* doc_struct; if ( xpop==NULL ) return Qnil; switch(xpop->type) { case XPATH_NODESET: + Data_Get_Struct(ctxt, xmlXPathContext, xctxt); + doc = xctxt->doc; + doc_val = (VALUE)xctxt->doc->_private; + Data_Get_Struct(doc_val, ruby_xml_document_t, doc_struct); + doc_struct->ref_count++; + xpop->user2 = (void*)doc_struct; + rval = Data_Wrap_Struct(cXMLXPathObject, ruby_xml_xpath_object_mark, ruby_xml_xpath_object_free,