libxml-ruby 4.1.1-x64-mingw-ucrt → 4.1.2-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,339 +1,340 @@
1
- #include "ruby_libxml.h"
2
- #include <libxml/xpathInternals.h>
3
-
4
- /*
5
- * Document-class: LibXML::XML::XPath::Object
6
- *
7
- * A collection of nodes returned from the evaluation of an XML::XPath
8
- * or XML::XPointer expression.
9
- */
10
-
11
- VALUE cXMLXPathObject;
12
-
13
-
14
- /* Memory management of xpath results is tricky. If a nodeset is
15
- returned, it generally consists of pointers to nodes in the
16
- original document. However, namespace nodes are handled differently -
17
- libxml creates copies of them instead. Thus, when an xmlXPathObjectPtr
18
- is freed, libxml iterates over the results to find the copied namespace
19
- nodes to free them.
20
-
21
- This causes problems for the bindings because the underlying document
22
- may be freed before the xmlXPathObjectPtr instance. This might seem
23
- counterintuitive since the xmlXPathObjectPtr marks the document.
24
- However, once both objects go out of scope, the order of their
25
- destruction is random.
26
-
27
- To deal with this, the wrapper code searches for the namespace nodes
28
- and wraps them in Ruby objects. When the Ruby objects go out of scope
29
- then the namespace nodes are freed. */
30
-
31
- static void rxml_xpath_object_free(rxml_xpath_object *rxpop)
32
- {
33
- /* We positively, absolutely cannot let libxml iterate over
34
- the nodeTab since if the underlying document has been
35
- freed the majority of entries are invalid, resulting in
36
- segmentation faults.*/
37
- if (rxpop->xpop->nodesetval && rxpop->xpop->nodesetval->nodeTab)
38
- {
39
- xmlFree(rxpop->xpop->nodesetval->nodeTab);
40
- rxpop->xpop->nodesetval->nodeTab = NULL;
41
- }
42
- xmlXPathFreeObject(rxpop->xpop);
43
- xfree(rxpop);
44
- }
45
-
46
- /* Custom free function for copied namespace nodes */
47
- static void rxml_xpath_namespace_free(xmlNsPtr xns)
48
- {
49
- xmlFreeNs(xns);
50
- }
51
-
52
- static void rxml_xpath_object_mark(rxml_xpath_object *rxpop)
53
- {
54
- VALUE doc = (VALUE)rxpop->xdoc->_private;
55
- rb_gc_mark(doc);
56
- rb_gc_mark(rxpop->nsnodes);
57
- }
58
-
59
- VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
60
- {
61
- int i;
62
- rxml_xpath_object *rxpop = ALLOC(rxml_xpath_object);
63
-
64
- /* Make sure Ruby's GC can find the array in the stack */
65
- VALUE nsnodes = rb_ary_new();
66
- rxpop->xdoc =xdoc;
67
- rxpop->xpop = xpop;
68
-
69
- /* Find all the extra namespace nodes and wrap them. */
70
- if (xpop->nodesetval && xpop->nodesetval->nodeNr)
71
- {
72
- for (i = 0; i < xpop->nodesetval->nodeNr; i++)
73
- {
74
- xmlNodePtr xnode = xpop->nodesetval->nodeTab[i];
75
- if (xnode != NULL && xnode->type == XML_NAMESPACE_DECL)
76
- {
77
- VALUE ns = Qnil;
78
- xmlNsPtr xns = (xmlNsPtr)xnode;
79
-
80
- /* Get rid of libxml's -> next hack. The issue here is
81
- the rxml_namespace code assumes that ns->next refers
82
- to another namespace. */
83
- xns->next = NULL;
84
-
85
- /* Specify a custom free function here since by default
86
- namespace nodes will not be freed */
87
- ns = rxml_namespace_wrap((xmlNsPtr)xnode);
88
- RDATA(ns)->dfree = (RUBY_DATA_FUNC)rxml_xpath_namespace_free;
89
- rb_ary_push(nsnodes, ns);
90
- }
91
- }
92
- }
93
-
94
- rxpop->nsnodes = nsnodes;
95
- return Data_Wrap_Struct(cXMLXPathObject, rxml_xpath_object_mark, rxml_xpath_object_free, rxpop);
96
- }
97
-
98
- static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int index)
99
- {
100
- if (index < 0)
101
- index = xpop->nodesetval->nodeNr + index;
102
-
103
- if (index < 0 || index + 1 > xpop->nodesetval->nodeNr)
104
- return Qnil;
105
-
106
- switch (xpop->nodesetval->nodeTab[index]->type)
107
- {
108
- case XML_ATTRIBUTE_NODE:
109
- return rxml_attr_wrap((xmlAttrPtr) xpop->nodesetval->nodeTab[index]);
110
- break;
111
- case XML_NAMESPACE_DECL:
112
- return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[index]);
113
- break;
114
- default:
115
- return rxml_node_wrap(xpop->nodesetval->nodeTab[index]);
116
- }
117
- }
118
-
119
- /*
120
- * call-seq:
121
- * xpath_object.to_a -> [node, ..., node]
122
- *
123
- * Obtain an array of the nodes in this set.
124
- */
125
- static VALUE rxml_xpath_object_to_a(VALUE self)
126
- {
127
- VALUE set_ary, nodeobj;
128
- rxml_xpath_object *rxpop;
129
- xmlXPathObjectPtr xpop;
130
- int i;
131
-
132
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
133
- xpop = rxpop->xpop;
134
-
135
- set_ary = rb_ary_new();
136
-
137
- if (!((xpop->nodesetval == NULL) || (xpop->nodesetval->nodeNr == 0)))
138
- {
139
- for (i = 0; i < xpop->nodesetval->nodeNr; i++)
140
- {
141
- nodeobj = rxml_xpath_object_tabref(xpop, i);
142
- rb_ary_push(set_ary, nodeobj);
143
- }
144
- }
145
-
146
- return (set_ary);
147
- }
148
-
149
- /*
150
- * call-seq:
151
- * xpath_object.empty? -> (true|false)
152
- *
153
- * Determine whether this nodeset is empty (contains no nodes).
154
- */
155
- static VALUE rxml_xpath_object_empty_q(VALUE self)
156
- {
157
- rxml_xpath_object *rxpop;
158
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
159
-
160
- if (rxpop->xpop->type != XPATH_NODESET)
161
- return Qnil;
162
-
163
- return (rxpop->xpop->nodesetval == NULL || rxpop->xpop->nodesetval->nodeNr <= 0) ? Qtrue
164
- : Qfalse;
165
- }
166
-
167
- /*
168
- * call-seq:
169
- * xpath_object.each { |node| ... } -> self
170
- *
171
- * Call the supplied block for each node in this set.
172
- */
173
- static VALUE rxml_xpath_object_each(VALUE self)
174
- {
175
- rxml_xpath_object *rxpop;
176
- int i;
177
-
178
- if (rxml_xpath_object_empty_q(self) == Qtrue)
179
- return Qnil;
180
-
181
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
182
-
183
- for (i = 0; i < rxpop->xpop->nodesetval->nodeNr; i++)
184
- {
185
- rb_yield(rxml_xpath_object_tabref(rxpop->xpop, i));
186
- }
187
- return (self);
188
- }
189
-
190
- /*
191
- * call-seq:
192
- * xpath_object.first -> node
193
- *
194
- * Returns the first node in this node set, or nil if none exist.
195
- */
196
- static VALUE rxml_xpath_object_first(VALUE self)
197
- {
198
- rxml_xpath_object *rxpop;
199
-
200
- if (rxml_xpath_object_empty_q(self) == Qtrue)
201
- return Qnil;
202
-
203
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
204
- return rxml_xpath_object_tabref(rxpop->xpop, 0);
205
- }
206
-
207
- /*
208
- * call-seq:
209
- * xpath_object.last -> node
210
- *
211
- * Returns the last node in this node set, or nil if none exist.
212
- */
213
- static VALUE rxml_xpath_object_last(VALUE self)
214
- {
215
- rxml_xpath_object *rxpop;
216
-
217
- if (rxml_xpath_object_empty_q(self) == Qtrue)
218
- return Qnil;
219
-
220
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
221
- return rxml_xpath_object_tabref(rxpop->xpop, -1);
222
- }
223
-
224
- /*
225
- * call-seq:
226
- * xpath_object[i] -> node
227
- *
228
- * array index into set of nodes
229
- */
230
- static VALUE rxml_xpath_object_aref(VALUE self, VALUE aref)
231
- {
232
- rxml_xpath_object *rxpop;
233
-
234
- if (rxml_xpath_object_empty_q(self) == Qtrue)
235
- return Qnil;
236
-
237
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
238
- return rxml_xpath_object_tabref(rxpop->xpop, NUM2INT(aref));
239
- }
240
-
241
- /*
242
- * call-seq:
243
- * xpath_object.length -> num
244
- *
245
- * Obtain the length of the nodesetval node list.
246
- */
247
- static VALUE rxml_xpath_object_length(VALUE self)
248
- {
249
- rxml_xpath_object *rxpop;
250
-
251
- if (rxml_xpath_object_empty_q(self) == Qtrue)
252
- return INT2FIX(0);
253
-
254
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
255
- return INT2NUM(rxpop->xpop->nodesetval->nodeNr);
256
- }
257
-
258
- /*
259
- * call-seq:
260
- * xpath_object.xpath_type -> int
261
- *
262
- * Returns the XPath type of the result object.
263
- * Possible values are defined as constants
264
- * on the XML::XPath class and include:
265
- *
266
- * * XML::XPath::UNDEFINED
267
- * * XML::XPath::NODESET
268
- * * XML::XPath::BOOLEAN
269
- * * XML::XPath::NUMBER
270
- * * XML::XPath::STRING
271
- * * XML::XPath::POINT
272
- * * XML::XPath::RANGE
273
- * * XML::XPath::LOCATIONSET
274
- * * XML::XPath::USERS
275
- * * XML::XPath::XSLT_TREE
276
- */
277
- static VALUE rxml_xpath_object_get_type(VALUE self)
278
- {
279
- rxml_xpath_object *rxpop;
280
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
281
- return INT2FIX(rxpop->xpop->type);
282
- }
283
-
284
- /*
285
- * call-seq:
286
- * xpath_object.string -> String
287
- *
288
- * Returns the original XPath expression as a string.
289
- */
290
- static VALUE rxml_xpath_object_string(VALUE self)
291
- {
292
- rxml_xpath_object *rxpop;
293
-
294
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
295
-
296
- if (rxpop->xpop->stringval == NULL)
297
- return Qnil;
298
-
299
- return rxml_new_cstr( rxpop->xpop->stringval, rxpop->xdoc->encoding);
300
- }
301
-
302
- /*
303
- * call-seq:
304
- * nodes.debug -> (true|false)
305
- *
306
- * Dump libxml debugging information to stdout.
307
- * Requires Libxml be compiled with debugging enabled.
308
- */
309
- static VALUE rxml_xpath_object_debug(VALUE self)
310
- {
311
- #ifdef LIBXML_DEBUG_ENABLED
312
- rxml_xpath_object *rxpop;
313
- Data_Get_Struct(self, rxml_xpath_object, rxpop);
314
- xmlXPathDebugDumpObject(stdout, rxpop->xpop, 0);
315
- return Qtrue;
316
- #else
317
- rb_warn("libxml was compiled without debugging support.");
318
- return Qfalse;
319
- #endif
320
- }
321
-
322
- void rxml_init_xpath_object(void)
323
- {
324
- cXMLXPathObject = rb_define_class_under(mXPath, "Object", rb_cObject);
325
- rb_include_module(cXMLXPathObject, rb_mEnumerable);
326
- rb_define_attr(cXMLXPathObject, "context", 1, 0);
327
- rb_define_method(cXMLXPathObject, "each", rxml_xpath_object_each, 0);
328
- rb_define_method(cXMLXPathObject, "xpath_type", rxml_xpath_object_get_type, 0);
329
- rb_define_method(cXMLXPathObject, "empty?", rxml_xpath_object_empty_q, 0);
330
- rb_define_method(cXMLXPathObject, "first", rxml_xpath_object_first, 0);
331
- rb_define_method(cXMLXPathObject, "last", rxml_xpath_object_last, 0);
332
- rb_define_method(cXMLXPathObject, "length", rxml_xpath_object_length, 0);
333
- rb_define_method(cXMLXPathObject, "to_a", rxml_xpath_object_to_a, 0);
334
- rb_define_method(cXMLXPathObject, "[]", rxml_xpath_object_aref, 1);
335
- rb_define_method(cXMLXPathObject, "string", rxml_xpath_object_string, 0);
336
- rb_define_method(cXMLXPathObject, "debug", rxml_xpath_object_debug, 0);
337
- rb_define_alias(cXMLXPathObject, "size", "length");
338
-
339
- }
1
+ #include "ruby_libxml.h"
2
+ #include <libxml/xpathInternals.h>
3
+
4
+ /*
5
+ * Document-class: LibXML::XML::XPath::Object
6
+ *
7
+ * A collection of nodes returned from the evaluation of an XML::XPath
8
+ * or XML::XPointer expression.
9
+ */
10
+
11
+ VALUE cXMLXPathObject;
12
+
13
+
14
+ /* Memory management of xpath results is tricky. If a nodeset is
15
+ returned, it generally consists of pointers to nodes in the
16
+ original document. However, namespace nodes are handled differently -
17
+ libxml creates copies of them instead. Thus, when an xmlXPathObjectPtr
18
+ is freed, libxml iterates over the results to find the copied namespace
19
+ nodes to free them.
20
+
21
+ This causes problems for the bindings because the underlying document
22
+ may be freed before the xmlXPathObjectPtr instance. This might seem
23
+ counterintuitive since the xmlXPathObjectPtr marks the document.
24
+ However, once both objects go out of scope, the order of their
25
+ destruction is random.
26
+
27
+ To deal with this, the wrapper code searches for the namespace nodes
28
+ and wraps them in Ruby objects. When the Ruby objects go out of scope
29
+ then the namespace nodes are freed. */
30
+
31
+ static void rxml_xpath_object_free(rxml_xpath_object *rxpop)
32
+ {
33
+ /* We positively, absolutely cannot let libxml iterate over
34
+ the nodeTab since if the underlying document has been
35
+ freed the majority of entries are invalid, resulting in
36
+ segmentation faults.*/
37
+ if (rxpop->xpop->nodesetval && rxpop->xpop->nodesetval->nodeTab)
38
+ {
39
+ xmlFree(rxpop->xpop->nodesetval->nodeTab);
40
+ rxpop->xpop->nodesetval->nodeTab = NULL;
41
+ }
42
+ xmlXPathFreeObject(rxpop->xpop);
43
+ xfree(rxpop);
44
+ }
45
+
46
+ /* Custom free function for copied namespace nodes */
47
+ static void rxml_xpath_namespace_free(xmlNsPtr xns)
48
+ {
49
+ xmlFreeNs(xns);
50
+ }
51
+
52
+ static void rxml_xpath_object_mark(rxml_xpath_object *rxpop)
53
+ {
54
+ VALUE doc = (VALUE)rxpop->xdoc->_private;
55
+ rb_gc_mark(doc);
56
+ rb_gc_mark(rxpop->nsnodes);
57
+ }
58
+
59
+ VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
60
+ {
61
+ int i;
62
+ rxml_xpath_object *rxpop = ALLOC(rxml_xpath_object);
63
+
64
+ /* Make sure Ruby's GC can find the array in the stack */
65
+ VALUE nsnodes = rb_ary_new();
66
+ rxpop->xdoc =xdoc;
67
+ rxpop->xpop = xpop;
68
+
69
+ /* Find all the extra namespace nodes and wrap them. */
70
+ if (xpop->nodesetval && xpop->nodesetval->nodeNr)
71
+ {
72
+ for (i = 0; i < xpop->nodesetval->nodeNr; i++)
73
+ {
74
+ xmlNodePtr xnode = xpop->nodesetval->nodeTab[i];
75
+ if (xnode != NULL && xnode->type == XML_NAMESPACE_DECL)
76
+ {
77
+ VALUE ns = Qnil;
78
+ xmlNsPtr xns = (xmlNsPtr)xnode;
79
+
80
+ /* Get rid of libxml's -> next hack. The issue here is
81
+ the rxml_namespace code assumes that ns->next refers
82
+ to another namespace. */
83
+ xns->next = NULL;
84
+
85
+ /* Specify a custom free function here since by default
86
+ namespace nodes will not be freed */
87
+ ns = rxml_namespace_wrap((xmlNsPtr)xnode);
88
+ RDATA(ns)->dfree = (RUBY_DATA_FUNC)rxml_xpath_namespace_free;
89
+ rb_ary_push(nsnodes, ns);
90
+ }
91
+ }
92
+ }
93
+
94
+ rxpop->nsnodes = nsnodes;
95
+ return Data_Wrap_Struct(cXMLXPathObject, rxml_xpath_object_mark, rxml_xpath_object_free, rxpop);
96
+ }
97
+
98
+ static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int index)
99
+ {
100
+ if (index < 0)
101
+ index = xpop->nodesetval->nodeNr + index;
102
+
103
+ if (index < 0 || index + 1 > xpop->nodesetval->nodeNr)
104
+ return Qnil;
105
+
106
+ switch (xpop->nodesetval->nodeTab[index]->type)
107
+ {
108
+ case XML_ATTRIBUTE_NODE:
109
+ return rxml_attr_wrap((xmlAttrPtr) xpop->nodesetval->nodeTab[index]);
110
+ break;
111
+ case XML_NAMESPACE_DECL:
112
+ return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[index]);
113
+ break;
114
+ default:
115
+ return rxml_node_wrap(xpop->nodesetval->nodeTab[index]);
116
+ }
117
+ }
118
+
119
+ /*
120
+ * call-seq:
121
+ * xpath_object.to_a -> [node, ..., node]
122
+ *
123
+ * Obtain an array of the nodes in this set.
124
+ */
125
+ static VALUE rxml_xpath_object_to_a(VALUE self)
126
+ {
127
+ VALUE set_ary, nodeobj;
128
+ rxml_xpath_object *rxpop;
129
+ xmlXPathObjectPtr xpop;
130
+ int i;
131
+
132
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
133
+ xpop = rxpop->xpop;
134
+
135
+ set_ary = rb_ary_new();
136
+
137
+ if (!((xpop->nodesetval == NULL) || (xpop->nodesetval->nodeNr == 0)))
138
+ {
139
+ for (i = 0; i < xpop->nodesetval->nodeNr; i++)
140
+ {
141
+ nodeobj = rxml_xpath_object_tabref(xpop, i);
142
+ rb_ary_push(set_ary, nodeobj);
143
+ }
144
+ }
145
+
146
+ return (set_ary);
147
+ }
148
+
149
+ /*
150
+ * call-seq:
151
+ * xpath_object.empty? -> (true|false)
152
+ *
153
+ * Determine whether this nodeset is empty (contains no nodes).
154
+ */
155
+ static VALUE rxml_xpath_object_empty_q(VALUE self)
156
+ {
157
+ rxml_xpath_object *rxpop;
158
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
159
+
160
+ if (rxpop->xpop->type != XPATH_NODESET)
161
+ return Qnil;
162
+
163
+ return (rxpop->xpop->nodesetval == NULL || rxpop->xpop->nodesetval->nodeNr <= 0) ? Qtrue
164
+ : Qfalse;
165
+ }
166
+
167
+ /*
168
+ * call-seq:
169
+ * xpath_object.each { |node| ... } -> self
170
+ *
171
+ * Call the supplied block for each node in this set.
172
+ */
173
+ static VALUE rxml_xpath_object_each(VALUE self)
174
+ {
175
+ rxml_xpath_object *rxpop;
176
+ int i;
177
+
178
+ if (rxml_xpath_object_empty_q(self) == Qtrue)
179
+ return Qnil;
180
+
181
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
182
+
183
+ for (i = 0; i < rxpop->xpop->nodesetval->nodeNr; i++)
184
+ {
185
+ rb_yield(rxml_xpath_object_tabref(rxpop->xpop, i));
186
+ }
187
+ return (self);
188
+ }
189
+
190
+ /*
191
+ * call-seq:
192
+ * xpath_object.first -> node
193
+ *
194
+ * Returns the first node in this node set, or nil if none exist.
195
+ */
196
+ static VALUE rxml_xpath_object_first(VALUE self)
197
+ {
198
+ rxml_xpath_object *rxpop;
199
+
200
+ if (rxml_xpath_object_empty_q(self) == Qtrue)
201
+ return Qnil;
202
+
203
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
204
+ return rxml_xpath_object_tabref(rxpop->xpop, 0);
205
+ }
206
+
207
+ /*
208
+ * call-seq:
209
+ * xpath_object.last -> node
210
+ *
211
+ * Returns the last node in this node set, or nil if none exist.
212
+ */
213
+ static VALUE rxml_xpath_object_last(VALUE self)
214
+ {
215
+ rxml_xpath_object *rxpop;
216
+
217
+ if (rxml_xpath_object_empty_q(self) == Qtrue)
218
+ return Qnil;
219
+
220
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
221
+ return rxml_xpath_object_tabref(rxpop->xpop, -1);
222
+ }
223
+
224
+ /*
225
+ * call-seq:
226
+ * xpath_object[i] -> node
227
+ *
228
+ * array index into set of nodes
229
+ */
230
+ static VALUE rxml_xpath_object_aref(VALUE self, VALUE aref)
231
+ {
232
+ rxml_xpath_object *rxpop;
233
+
234
+ if (rxml_xpath_object_empty_q(self) == Qtrue)
235
+ return Qnil;
236
+
237
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
238
+ return rxml_xpath_object_tabref(rxpop->xpop, NUM2INT(aref));
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * xpath_object.length -> num
244
+ *
245
+ * Obtain the length of the nodesetval node list.
246
+ */
247
+ static VALUE rxml_xpath_object_length(VALUE self)
248
+ {
249
+ rxml_xpath_object *rxpop;
250
+
251
+ if (rxml_xpath_object_empty_q(self) == Qtrue)
252
+ return INT2FIX(0);
253
+
254
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
255
+ return INT2NUM(rxpop->xpop->nodesetval->nodeNr);
256
+ }
257
+
258
+ /*
259
+ * call-seq:
260
+ * xpath_object.xpath_type -> int
261
+ *
262
+ * Returns the XPath type of the result object.
263
+ * Possible values are defined as constants
264
+ * on the XML::XPath class and include:
265
+ *
266
+ * * XML::XPath::UNDEFINED
267
+ * * XML::XPath::NODESET
268
+ * * XML::XPath::BOOLEAN
269
+ * * XML::XPath::NUMBER
270
+ * * XML::XPath::STRING
271
+ * * XML::XPath::POINT
272
+ * * XML::XPath::RANGE
273
+ * * XML::XPath::LOCATIONSET
274
+ * * XML::XPath::USERS
275
+ * * XML::XPath::XSLT_TREE
276
+ */
277
+ static VALUE rxml_xpath_object_get_type(VALUE self)
278
+ {
279
+ rxml_xpath_object *rxpop;
280
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
281
+ return INT2FIX(rxpop->xpop->type);
282
+ }
283
+
284
+ /*
285
+ * call-seq:
286
+ * xpath_object.string -> String
287
+ *
288
+ * Returns the original XPath expression as a string.
289
+ */
290
+ static VALUE rxml_xpath_object_string(VALUE self)
291
+ {
292
+ rxml_xpath_object *rxpop;
293
+
294
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
295
+
296
+ if (rxpop->xpop->stringval == NULL)
297
+ return Qnil;
298
+
299
+ return rxml_new_cstr( rxpop->xpop->stringval, rxpop->xdoc->encoding);
300
+ }
301
+
302
+ /*
303
+ * call-seq:
304
+ * nodes.debug -> (true|false)
305
+ *
306
+ * Dump libxml debugging information to stdout.
307
+ * Requires Libxml be compiled with debugging enabled.
308
+ */
309
+ static VALUE rxml_xpath_object_debug(VALUE self)
310
+ {
311
+ #ifdef LIBXML_DEBUG_ENABLED
312
+ rxml_xpath_object *rxpop;
313
+ Data_Get_Struct(self, rxml_xpath_object, rxpop);
314
+ xmlXPathDebugDumpObject(stdout, rxpop->xpop, 0);
315
+ return Qtrue;
316
+ #else
317
+ rb_warn("libxml was compiled without debugging support.");
318
+ return Qfalse;
319
+ #endif
320
+ }
321
+
322
+ void rxml_init_xpath_object(void)
323
+ {
324
+ cXMLXPathObject = rb_define_class_under(mXPath, "Object", rb_cObject);
325
+ rb_undef_alloc_func(cXMLXPathObject);
326
+ rb_include_module(cXMLXPathObject, rb_mEnumerable);
327
+ rb_define_attr(cXMLXPathObject, "context", 1, 0);
328
+ rb_define_method(cXMLXPathObject, "each", rxml_xpath_object_each, 0);
329
+ rb_define_method(cXMLXPathObject, "xpath_type", rxml_xpath_object_get_type, 0);
330
+ rb_define_method(cXMLXPathObject, "empty?", rxml_xpath_object_empty_q, 0);
331
+ rb_define_method(cXMLXPathObject, "first", rxml_xpath_object_first, 0);
332
+ rb_define_method(cXMLXPathObject, "last", rxml_xpath_object_last, 0);
333
+ rb_define_method(cXMLXPathObject, "length", rxml_xpath_object_length, 0);
334
+ rb_define_method(cXMLXPathObject, "to_a", rxml_xpath_object_to_a, 0);
335
+ rb_define_method(cXMLXPathObject, "[]", rxml_xpath_object_aref, 1);
336
+ rb_define_method(cXMLXPathObject, "string", rxml_xpath_object_string, 0);
337
+ rb_define_method(cXMLXPathObject, "debug", rxml_xpath_object_debug, 0);
338
+ rb_define_alias(cXMLXPathObject, "size", "length");
339
+
340
+ }