libxml-ruby 4.1.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY +22 -0
  3. data/ext/libxml/extconf.rb +67 -61
  4. data/ext/libxml/ruby_libxml.h +43 -44
  5. data/ext/libxml/ruby_xml.c +0 -343
  6. data/ext/libxml/ruby_xml.h +9 -10
  7. data/ext/libxml/ruby_xml_attr_decl.c +154 -153
  8. data/ext/libxml/ruby_xml_attributes.c +276 -275
  9. data/ext/libxml/ruby_xml_attributes.h +2 -0
  10. data/ext/libxml/ruby_xml_document.c +6 -6
  11. data/ext/libxml/ruby_xml_document.h +11 -11
  12. data/ext/libxml/ruby_xml_dtd.c +3 -3
  13. data/ext/libxml/ruby_xml_encoding.h +20 -18
  14. data/ext/libxml/ruby_xml_error.c +9 -6
  15. data/ext/libxml/ruby_xml_error.h +2 -2
  16. data/ext/libxml/ruby_xml_html_parser_context.c +35 -21
  17. data/ext/libxml/ruby_xml_namespace.c +0 -3
  18. data/ext/libxml/ruby_xml_node.c +1394 -1398
  19. data/ext/libxml/ruby_xml_parser.h +1 -1
  20. data/ext/libxml/ruby_xml_parser_context.c +47 -39
  21. data/ext/libxml/ruby_xml_parser_options.c +9 -1
  22. data/ext/libxml/ruby_xml_parser_options.h +1 -1
  23. data/ext/libxml/ruby_xml_reader.c +1244 -1242
  24. data/ext/libxml/ruby_xml_relaxng.c +113 -112
  25. data/ext/libxml/ruby_xml_sax2_handler.c +1 -1
  26. data/ext/libxml/ruby_xml_sax_parser.c +1 -9
  27. data/ext/libxml/ruby_xml_schema.c +422 -420
  28. data/ext/libxml/ruby_xml_schema_attribute.c +108 -107
  29. data/ext/libxml/ruby_xml_schema_element.c +70 -69
  30. data/ext/libxml/ruby_xml_schema_type.c +252 -251
  31. data/ext/libxml/ruby_xml_version.h +5 -5
  32. data/ext/libxml/ruby_xml_writer.c +1138 -1137
  33. data/ext/libxml/ruby_xml_xpath.c +1 -1
  34. data/ext/libxml/ruby_xml_xpath_context.c +2 -2
  35. data/ext/libxml/ruby_xml_xpath_expression.c +81 -81
  36. data/ext/libxml/ruby_xml_xpath_object.c +340 -339
  37. data/lib/libxml/document.rb +13 -13
  38. data/lib/libxml/html_parser.rb +23 -23
  39. data/lib/libxml/parser.rb +26 -24
  40. data/lib/libxml/schema/element.rb +27 -19
  41. data/test/test.rb +5 -0
  42. data/test/test_document_write.rb +1 -4
  43. data/test/test_dtd.rb +1 -4
  44. data/test/test_encoding.rb +1 -4
  45. data/test/test_helper.rb +9 -2
  46. data/test/test_html_parser.rb +162 -162
  47. data/test/test_namespace.rb +1 -3
  48. data/test/test_node.rb +1 -3
  49. data/test/test_node_write.rb +1 -4
  50. data/test/test_parser.rb +26 -17
  51. data/test/test_reader.rb +4 -4
  52. data/test/test_sax_parser.rb +1 -1
  53. data/test/test_schema.rb +237 -231
  54. data/test/test_xml.rb +0 -99
  55. metadata +4 -3
@@ -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
+ }