2828
2929VALUE cXMLXPathContext ;
3030
31+ typedef struct rxml_xpath_context
32+ {
33+ xmlXPathContextPtr xctxt ;
34+ VALUE document ;
35+ } rxml_xpath_context ;
36+
3137static void rxml_xpath_context_free (void * data )
3238{
33- xmlXPathContextPtr ctxt = (xmlXPathContextPtr )data ;
34- xmlXPathFreeContext (ctxt );
39+ rxml_xpath_context * wrapper = (rxml_xpath_context * )data ;
40+ if (wrapper == NULL ) return ;
41+ if (wrapper -> xctxt )
42+ {
43+ xmlXPathFreeContext (wrapper -> xctxt );
44+ }
45+ xfree (wrapper );
3546}
3647
3748static void rxml_xpath_context_mark (void * data )
3849{
39- xmlXPathContextPtr ctxt = (xmlXPathContextPtr )data ;
40- if (ctxt == NULL ) return ;
41- VALUE value = (VALUE )ctxt -> doc -> _private ;
42- rb_gc_mark (value );
50+ rxml_xpath_context * wrapper = (rxml_xpath_context * )data ;
51+ if (wrapper == NULL ) return ;
52+ rb_gc_mark (wrapper -> document );
4353}
4454
4555static const rb_data_type_t rxml_xpath_context_data_type = {
@@ -67,14 +77,28 @@ static VALUE rxml_xpath_context_alloc(VALUE klass)
6777static VALUE rxml_xpath_context_initialize (VALUE self , VALUE document )
6878{
6979 xmlDocPtr xdoc ;
80+ rxml_xpath_context * wrapper ;
7081
7182 if (rb_obj_is_kind_of (document , cXMLDocument ) != Qtrue )
7283 {
7384 rb_raise (rb_eTypeError , "Supplied argument must be a document or node." );
7485 }
7586
7687 TypedData_Get_Struct (document , xmlDoc , & rxml_document_data_type , xdoc );
77- RTYPEDDATA_DATA (self ) = xmlXPathNewContext (xdoc );
88+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
89+
90+ if (wrapper == NULL )
91+ {
92+ wrapper = ALLOC (rxml_xpath_context );
93+ RTYPEDDATA_DATA (self ) = wrapper ;
94+ }
95+ else if (wrapper -> xctxt )
96+ {
97+ xmlXPathFreeContext (wrapper -> xctxt );
98+ }
99+
100+ wrapper -> document = document ;
101+ wrapper -> xctxt = xmlXPathNewContext (xdoc );
78102
79103 return self ;
80104}
@@ -87,12 +111,10 @@ static VALUE rxml_xpath_context_initialize(VALUE self, VALUE document)
87111 */
88112static VALUE rxml_xpath_context_doc (VALUE self )
89113{
90- xmlDocPtr xdoc = NULL ;
91- xmlXPathContextPtr ctxt ;
92- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , ctxt );
93-
94- xdoc = ctxt -> doc ;
95- return rxml_document_wrap (xdoc );
114+ rxml_xpath_context * wrapper ;
115+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
116+ if (wrapper == NULL ) return Qnil ;
117+ return wrapper -> document ;
96118}
97119
98120/*
@@ -106,8 +128,10 @@ static VALUE rxml_xpath_context_doc(VALUE self)
106128 */
107129static VALUE rxml_xpath_context_register_namespace (VALUE self , VALUE prefix , VALUE uri )
108130{
131+ rxml_xpath_context * wrapper ;
109132 xmlXPathContextPtr ctxt ;
110- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , ctxt );
133+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
134+ ctxt = wrapper -> xctxt ;
111135
112136 /* Prefix could be a symbol. */
113137 prefix = rb_obj_as_string (prefix );
@@ -137,11 +161,13 @@ static VALUE rxml_xpath_context_register_namespace(VALUE self, VALUE prefix, VAL
137161static VALUE rxml_xpath_context_register_namespaces_from_node (VALUE self ,
138162 VALUE node )
139163{
164+ rxml_xpath_context * wrapper ;
140165 xmlXPathContextPtr xctxt ;
141166 xmlNodePtr xnode ;
142167 xmlNsPtr * xnsArr ;
143168
144- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
169+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
170+ xctxt = wrapper -> xctxt ;
145171
146172 if (rb_obj_is_kind_of (node , cXMLDocument ) == Qtrue )
147173 {
@@ -207,9 +233,11 @@ static VALUE rxml_xpath_context_register_namespaces(VALUE self, VALUE nslist)
207233 char * cp ;
208234 long i ;
209235 VALUE rprefix , ruri ;
236+ rxml_xpath_context * wrapper ;
210237 xmlXPathContextPtr xctxt ;
211238
212- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
239+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
240+ xctxt = wrapper -> xctxt ;
213241
214242 /* Need to loop through the 2nd argument and iterate through the
215243 * list of namespaces that we want to allow */
@@ -258,10 +286,12 @@ static VALUE rxml_xpath_context_register_namespaces(VALUE self, VALUE nslist)
258286 */
259287static VALUE rxml_xpath_context_node_set (VALUE self , VALUE node )
260288{
289+ rxml_xpath_context * wrapper ;
261290 xmlXPathContextPtr xctxt ;
262291 xmlNodePtr xnode ;
263292
264- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
293+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
294+ xctxt = wrapper -> xctxt ;
265295 TypedData_Get_Struct (node , xmlNode , & rxml_node_data_type , xnode );
266296 xctxt -> node = xnode ;
267297 return node ;
@@ -277,11 +307,13 @@ static VALUE rxml_xpath_context_node_set(VALUE self, VALUE node)
277307 */
278308static VALUE rxml_xpath_context_find (VALUE self , VALUE xpath_expr )
279309{
310+ rxml_xpath_context * wrapper ;
280311 xmlXPathContextPtr xctxt ;
281312 xmlXPathObjectPtr xobject ;
282313 xmlXPathCompExprPtr xcompexpr ;
283314
284- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
315+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
316+ xctxt = wrapper -> xctxt ;
285317
286318 if (TYPE (xpath_expr ) == T_STRING )
287319 {
@@ -299,7 +331,7 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
299331 "Argument should be an instance of a String or XPath::Expression" );
300332 }
301333
302- return rxml_xpath_to_value (xctxt , xobject );
334+ return rxml_xpath_to_value (wrapper -> document , xctxt , xobject );
303335}
304336
305337#if LIBXML_VERSION >= 20626
@@ -317,11 +349,13 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
317349static VALUE
318350rxml_xpath_context_enable_cache (int argc , VALUE * argv , VALUE self )
319351{
352+ rxml_xpath_context * wrapper ;
320353 xmlXPathContextPtr xctxt ;
321354 VALUE size ;
322355 int value = -1 ;
323356
324- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
357+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
358+ xctxt = wrapper -> xctxt ;
325359
326360 if (rb_scan_args (argc , argv , "01" , & size ) == 1 )
327361 {
@@ -343,8 +377,10 @@ rxml_xpath_context_enable_cache(int argc, VALUE *argv, VALUE self)
343377static VALUE
344378rxml_xpath_context_disable_cache (VALUE self )
345379{
380+ rxml_xpath_context * wrapper ;
346381 xmlXPathContextPtr xctxt ;
347- TypedData_Get_Struct (self , xmlXPathContext , & rxml_xpath_context_data_type , xctxt );
382+ TypedData_Get_Struct (self , rxml_xpath_context , & rxml_xpath_context_data_type , wrapper );
383+ xctxt = wrapper -> xctxt ;
348384
349385 if (xmlXPathContextSetCache (xctxt , 0 , 0 , 0 ) == -1 )
350386 rxml_raise (xmlGetLastError ());
0 commit comments