libxml-ruby 2.7.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +6 -14
  2. data/HISTORY +33 -11
  3. data/README.rdoc +7 -7
  4. data/Rakefile +80 -77
  5. data/ext/libxml/extconf.h +4 -5
  6. data/ext/libxml/extconf.rb +57 -118
  7. data/ext/libxml/libxml.c +4 -0
  8. data/ext/libxml/ruby_xml.c +977 -893
  9. data/ext/libxml/ruby_xml.h +20 -10
  10. data/ext/libxml/ruby_xml_attr.c +333 -333
  11. data/ext/libxml/ruby_xml_attr_decl.c +2 -2
  12. data/ext/libxml/ruby_xml_cbg.c +85 -85
  13. data/ext/libxml/ruby_xml_document.c +1133 -1147
  14. data/ext/libxml/ruby_xml_dtd.c +261 -268
  15. data/ext/libxml/ruby_xml_encoding.c +262 -260
  16. data/ext/libxml/ruby_xml_encoding.h +19 -19
  17. data/ext/libxml/ruby_xml_html_parser_context.c +337 -338
  18. data/ext/libxml/ruby_xml_input_cbg.c +191 -191
  19. data/ext/libxml/ruby_xml_io.c +52 -50
  20. data/ext/libxml/ruby_xml_namespace.c +2 -2
  21. data/ext/libxml/ruby_xml_node.c +1446 -1452
  22. data/ext/libxml/ruby_xml_parser_context.c +999 -1001
  23. data/ext/libxml/ruby_xml_reader.c +1226 -1228
  24. data/ext/libxml/ruby_xml_relaxng.c +110 -111
  25. data/ext/libxml/ruby_xml_sax2_handler.c +326 -328
  26. data/ext/libxml/ruby_xml_schema.c +300 -301
  27. data/ext/libxml/ruby_xml_version.h +3 -3
  28. data/ext/libxml/ruby_xml_writer.c +34 -16
  29. data/ext/libxml/ruby_xml_xpath.c +188 -187
  30. data/ext/libxml/ruby_xml_xpath_context.c +360 -361
  31. data/ext/libxml/ruby_xml_xpath_object.c +335 -335
  32. data/libxml-ruby.gemspec +47 -44
  33. data/test/tc_attr.rb +5 -7
  34. data/test/tc_attr_decl.rb +5 -6
  35. data/test/tc_attributes.rb +1 -2
  36. data/test/tc_canonicalize.rb +1 -2
  37. data/test/tc_deprecated_require.rb +1 -2
  38. data/test/tc_document.rb +4 -5
  39. data/test/tc_document_write.rb +2 -3
  40. data/test/tc_dtd.rb +4 -5
  41. data/test/tc_encoding.rb +126 -126
  42. data/test/tc_encoding_sax.rb +4 -3
  43. data/test/tc_error.rb +14 -15
  44. data/test/tc_html_parser.rb +15 -7
  45. data/test/tc_html_parser_context.rb +1 -2
  46. data/test/tc_namespace.rb +2 -3
  47. data/test/tc_namespaces.rb +5 -6
  48. data/test/tc_node.rb +2 -3
  49. data/test/tc_node_cdata.rb +2 -3
  50. data/test/tc_node_comment.rb +1 -2
  51. data/test/tc_node_copy.rb +1 -2
  52. data/test/tc_node_edit.rb +5 -7
  53. data/test/tc_node_pi.rb +1 -2
  54. data/test/tc_node_text.rb +2 -3
  55. data/test/tc_node_write.rb +2 -3
  56. data/test/tc_node_xlink.rb +1 -2
  57. data/test/tc_parser.rb +18 -24
  58. data/test/tc_parser_context.rb +6 -7
  59. data/test/tc_properties.rb +1 -2
  60. data/test/tc_reader.rb +9 -10
  61. data/test/tc_relaxng.rb +4 -5
  62. data/test/tc_sax_parser.rb +9 -10
  63. data/test/tc_schema.rb +4 -5
  64. data/test/tc_traversal.rb +1 -2
  65. data/test/tc_writer.rb +1 -2
  66. data/test/tc_xinclude.rb +1 -2
  67. data/test/tc_xml.rb +1 -2
  68. data/test/tc_xpath.rb +8 -9
  69. data/test/tc_xpath_context.rb +3 -4
  70. data/test/tc_xpath_expression.rb +3 -4
  71. data/test/tc_xpointer.rb +1 -3
  72. data/test/test_helper.rb +3 -1
  73. data/test/test_suite.rb +0 -1
  74. metadata +90 -72
  75. data/test/etc_doc_to_s.rb +0 -21
  76. data/test/ets_doc_file.rb +0 -17
  77. data/test/ets_doc_to_s.rb +0 -23
  78. data/test/ets_gpx.rb +0 -28
  79. data/test/ets_node_gc.rb +0 -23
  80. data/test/ets_test.xml +0 -2
  81. data/test/ets_tsr.rb +0 -11
  82. data/test/model/kml_sample.xml +0 -915
  83. data/test/remove_test.rb +0 -9
  84. data/test/tc_gc.rb +0 -86
  85. data/test/tc_parser.rb.orig +0 -384
@@ -34,6 +34,7 @@ typedef struct {
34
34
  xmlBufferPtr buffer;
35
35
  xmlTextWriterPtr writer;
36
36
  rxmlw_output_type output_type;
37
+ int closed;
37
38
  } rxml_writer_object;
38
39
 
39
40
  #ifdef HAVE_RUBY_ENCODING_H
@@ -72,6 +73,8 @@ static void rxml_writer_free(rxml_writer_object *rwo)
72
73
  xmlBufferFree(rwo->buffer);
73
74
  }
74
75
  #endif
76
+
77
+ rwo->closed = 1;
75
78
  xmlFreeTextWriter(rwo->writer);
76
79
  xfree(rwo);
77
80
  }
@@ -97,6 +100,17 @@ static rxml_writer_object *rxml_textwriter_get(VALUE obj)
97
100
  return rwo;
98
101
  }
99
102
 
103
+ int rxml_writer_write_callback(void *context, const char *buffer, int len)
104
+ {
105
+ rxml_writer_object *rwo = context;
106
+
107
+ if(rwo->closed){
108
+ return 0;
109
+ }else{
110
+ return rxml_write_callback((void *)rwo->output, buffer, len);
111
+ }
112
+ }
113
+
100
114
  /* ===== public class methods ===== */
101
115
 
102
116
  /* call-seq:
@@ -122,11 +136,12 @@ xmlCharEncodingHandlerPtr xmlFindCharEncodingHandler(const char * name);
122
136
  rwo = ALLOC(rxml_writer_object);
123
137
  rwo->output = io;
124
138
  rwo->buffer = NULL;
139
+ rwo->closed = 0;
125
140
  #ifdef HAVE_RUBY_ENCODING_H
126
141
  rwo->encoding = NULL;
127
142
  #endif /* HAVE_RUBY_ENCODING_H */
128
143
  rwo->output_type = RXMLW_OUTPUT_IO;
129
- if (NULL == (out = xmlOutputBufferCreateIO(rxml_write_callback, NULL, (void *) io, NULL))) {
144
+ if (NULL == (out = xmlOutputBufferCreateIO(rxml_writer_write_callback, NULL, (void *) rwo, NULL))) {
130
145
  rxml_raise(&xmlLastError);
131
146
  }
132
147
  if (NULL == (rwo->writer = xmlNewTextWriter(out))) {
@@ -150,6 +165,7 @@ static VALUE rxml_writer_file(VALUE klass, VALUE filename)
150
165
  rwo = ALLOC(rxml_writer_object);
151
166
  rwo->output = Qnil;
152
167
  rwo->buffer = NULL;
168
+ rwo->closed = 0;
153
169
  #ifdef HAVE_RUBY_ENCODING_H
154
170
  rwo->encoding = NULL;
155
171
  #endif /* HAVE_RUBY_ENCODING_H */
@@ -172,6 +188,7 @@ static VALUE rxml_writer_string(VALUE klass)
172
188
 
173
189
  rwo = ALLOC(rxml_writer_object);
174
190
  rwo->output = Qnil;
191
+ rwo->closed = 0;
175
192
  #ifdef HAVE_RUBY_ENCODING_H
176
193
  rwo->encoding = NULL;
177
194
  #endif /* HAVE_RUBY_ENCODING_H */
@@ -200,6 +217,7 @@ static VALUE rxml_writer_doc(VALUE klass)
200
217
  rwo = ALLOC(rxml_writer_object);
201
218
  rwo->buffer = NULL;
202
219
  rwo->output = Qnil;
220
+ rwo->closed = 0;
203
221
  #ifdef HAVE_RUBY_ENCODING_H
204
222
  rwo->encoding = NULL;
205
223
  #endif /* HAVE_RUBY_ENCODING_H */
@@ -234,11 +252,12 @@ static VALUE rxml_writer_flush(int argc, VALUE *argv, VALUE self)
234
252
  if (-1 == (ret = xmlTextWriterFlush(rwo->writer))) {
235
253
  rxml_raise(&xmlLastError);
236
254
  }
255
+
237
256
  if (NULL != rwo->buffer) {
238
257
  VALUE content;
239
258
 
240
259
  #ifdef HAVE_RUBY_ENCODING_H
241
- content = rb_external_str_new_with_enc(rwo->buffer->content, rwo->buffer->use, rwo->encoding);
260
+ content = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
242
261
  #else
243
262
  content = rb_str_new(rwo->buffer->content, rwo->buffer->use);
244
263
  #endif /* HAVE_RUBY_ENCODING_H */
@@ -261,20 +280,20 @@ static VALUE rxml_writer_flush(int argc, VALUE *argv, VALUE self)
261
280
  */
262
281
  static VALUE rxml_writer_result(VALUE self)
263
282
  {
264
- VALUE ret;
265
- rxml_writer_object *rwo;
283
+ VALUE ret = Qnil;
284
+ rxml_writer_object *rwo = rxml_textwriter_get(self);
285
+ int bytesWritten = xmlTextWriterFlush(rwo->writer);
266
286
 
267
- ret = Qnil;
268
- rwo = rxml_textwriter_get(self);
269
- if (-1 == (ret = xmlTextWriterFlush(rwo->writer))) {
287
+ if (bytesWritten == -1) {
270
288
  rxml_raise(&xmlLastError);
271
289
  }
290
+
272
291
  switch (rwo->output_type) {
273
292
  case RXMLW_OUTPUT_DOC:
274
293
  ret = rwo->output;
275
294
  break;
276
295
  case RXMLW_OUTPUT_STRING:
277
- ret = rxml_writer_c_to_ruby_string(rwo->buffer->content, rwo->buffer->use);
296
+ ret = rxml_writer_c_to_ruby_string((const char*)rwo->buffer->content, rwo->buffer->use);
278
297
  break;
279
298
  case RXMLW_OUTPUT_IO:
280
299
  case RXMLW_OUTPUT_NONE:
@@ -315,7 +334,8 @@ static VALUE numeric_rxml_writer_void(VALUE obj, int (*fn)(xmlTextWriterPtr))
315
334
  static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_count, int (*fn)(ANYARGS), ...)
316
335
  {
317
336
  va_list ap;
318
- int argc, ret;
337
+ size_t argc;
338
+ int ret = -1;
319
339
  rxml_writer_object *rwo;
320
340
  const xmlChar *argv[XMLWRITER_MAX_STRING_ARGS];
321
341
  VALUE utf8[XMLWRITER_MAX_STRING_ARGS], orig[XMLWRITER_MAX_STRING_ARGS];
@@ -323,7 +343,6 @@ static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_
323
343
  if (strings_count > XMLWRITER_MAX_STRING_ARGS) {
324
344
  rb_bug("more arguments than expected");
325
345
  }
326
- ret = -1;
327
346
  va_start(ap, fn);
328
347
  rwo = rxml_textwriter_get(obj);
329
348
  for (argc = 0; argc < strings_count; argc++) {
@@ -746,12 +765,11 @@ static VALUE rxml_writer_end_cdata(VALUE self)
746
765
  static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
747
766
  {
748
767
  int ret;
749
- VALUE options;
768
+ VALUE options = Qnil;
750
769
  rxml_writer_object *rwo;
751
- const char *xencoding, *xstandalone;
770
+ const xmlChar *xencoding = NULL;
771
+ const char *xstandalone = NULL;
752
772
 
753
- options = Qnil;
754
- xstandalone = xencoding = NULL;
755
773
  rb_scan_args(argc, argv, "01", &options);
756
774
  if (!NIL_P(options)) {
757
775
  VALUE encoding, standalone;
@@ -759,7 +777,7 @@ static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
759
777
  encoding = standalone = Qnil;
760
778
  Check_Type(options, T_HASH);
761
779
  encoding = rb_hash_aref(options, sEncoding);
762
- xencoding = NIL_P(encoding) ? NULL : xmlGetCharEncodingName(NUM2INT(encoding));
780
+ xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
763
781
  standalone = rb_hash_aref(options, sStandalone);
764
782
  if (NIL_P(standalone)) {
765
783
  xstandalone = NULL;
@@ -771,7 +789,7 @@ static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
771
789
  #ifdef HAVE_RUBY_ENCODING_H
772
790
  rwo->encoding = rxml_figure_encoding(xencoding);
773
791
  #endif /* !HAVE_RUBY_ENCODING_H */
774
- ret = xmlTextWriterStartDocument(rwo->writer, NULL, xencoding, xstandalone);
792
+ ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
775
793
 
776
794
  return (-1 == ret ? Qfalse : Qtrue);
777
795
  }
@@ -1,187 +1,188 @@
1
- /*
2
- * Document-class: LibXML::XML::XPath
3
- *
4
- * The XML::XPath module is used to query XML documents. It is
5
- * usually accessed via the XML::Document#find or
6
- * XML::Node#find methods. For example:
7
- *
8
- * document.find('/foo', namespaces) -> XML::XPath::Object
9
- *
10
- * The optional namespaces parameter can be a string, array or
11
- * hash table.
12
- *
13
- * document.find('/foo', 'xlink:http://www.w3.org/1999/xlink')
14
- * document.find('/foo', ['xlink:http://www.w3.org/1999/xlink',
15
- * 'xi:http://www.w3.org/2001/XInclude')
16
- * document.find('/foo', 'xlink' => 'http://www.w3.org/1999/xlink',
17
- * 'xi' => 'http://www.w3.org/2001/XInclude')
18
- *
19
- *
20
- * === Working With Default Namespaces
21
- *
22
- * Finding namespaced elements and attributes can be tricky.
23
- * Lets work through an example of a document with a default
24
- * namespace:
25
- *
26
- * <?xml version="1.0" encoding="utf-8"?>
27
- * <feed xmlns="http://www.w3.org/2005/Atom">
28
- * <title type="text">Phil Bogle's Contacts</title>
29
- * </feed>
30
- *
31
- * To find nodes you must define the atom namespace for
32
- * libxml. One way to do this is:
33
- *
34
- * node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
35
- *
36
- * Alternatively, you can register the default namespace like this:
37
- *
38
- * doc.root.namespaces.default_prefix = 'atom'
39
- * node = doc.find('atom:title')
40
- *
41
- * === More Complex Namespace Examples
42
- *
43
- * Lets work through some more complex examples using the
44
- * following xml document:
45
- *
46
- * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
47
- * <soap:Body>
48
- * <getManufacturerNamesResponse xmlns="http://services.somewhere.com">
49
- * <IDAndNameList xmlns="http://services.somewhere.com">
50
- * <ns1:IdAndName xmlns:ns1="http://domain.somewhere.com"/>
51
- * </IDAndNameList>
52
- * </getManufacturerNamesResponse>
53
- * </soap:Envelope>
54
- *
55
- * # Since the soap namespace is defined on the root
56
- * # node we can directly use it.
57
- * doc.find('/soap:Envelope')
58
- *
59
- * # Since the ns1 namespace is not defined on the root node
60
- * # we have to first register it with the xpath engine.
61
- * doc.find('//ns1:IdAndName',
62
- * 'ns1:http://domain.somewhere.com')
63
- *
64
- * # Since the getManufacturerNamesResponse element uses a default
65
- * # namespace we first have to give it a prefix and register
66
- * # it with the xpath engine.
67
- * doc.find('//ns:getManufacturerNamesResponse',
68
- * 'ns:http://services.somewhere.com')
69
- *
70
- * # Here is an example showing a complex namespace aware
71
- * # xpath expression.
72
- * doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName',
73
- * ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com'])
74
- */
75
-
76
-
77
- #include "ruby_libxml.h"
78
-
79
- VALUE mXPath;
80
-
81
- VALUE
82
- rxml_xpath_to_value(xmlXPathContextPtr xctxt, xmlXPathObjectPtr xobject) {
83
- VALUE result;
84
- int type;
85
-
86
- if (xobject == NULL) {
87
- /* xmlLastError is different than xctxt->lastError. Use
88
- xmlLastError since it has the message set while xctxt->lastError
89
- does not. */
90
- xmlErrorPtr xerror = xmlGetLastError();
91
- rxml_raise(xerror);
92
- }
93
-
94
- switch (type = xobject->type) {
95
- case XPATH_NODESET:
96
- result = rxml_xpath_object_wrap(xctxt->doc, xobject);
97
- break;
98
- case XPATH_BOOLEAN:
99
- result = (xobject->boolval != 0) ? Qtrue : Qfalse;
100
- xmlXPathFreeObject(xobject);
101
- break;
102
- case XPATH_NUMBER:
103
- result = rb_float_new(xobject->floatval);
104
- xmlXPathFreeObject(xobject);
105
- break;
106
- case XPATH_STRING:
107
- result = rxml_new_cstr((const char*)xobject->stringval, xctxt->doc->encoding);
108
- xmlXPathFreeObject(xobject);
109
- break;
110
- default:
111
- xmlXPathFreeObject(xobject);
112
- rb_raise(rb_eTypeError,
113
- "can't convert XPath object of type %d to Ruby value", type
114
- );
115
- }
116
-
117
- return result;
118
- }
119
-
120
- xmlXPathObjectPtr
121
- rxml_xpath_from_value(VALUE value) {
122
- xmlXPathObjectPtr result = NULL;
123
-
124
- switch (TYPE(value)) {
125
- case T_TRUE:
126
- case T_FALSE:
127
- result = xmlXPathNewBoolean(RTEST(value));
128
- break;
129
- case T_FIXNUM:
130
- case T_FLOAT:
131
- result = xmlXPathNewFloat(NUM2DBL(value));
132
- break;
133
- case T_STRING:
134
- result = xmlXPathWrapString(xmlStrdup((const xmlChar *)StringValuePtr(value)));
135
- break;
136
- case T_NIL:
137
- result = xmlXPathNewNodeSet(NULL);
138
- break;
139
- case T_ARRAY: {
140
- int i, j;
141
- result = xmlXPathNewNodeSet(NULL);
142
-
143
- for (i = RARRAY_LEN(value); i > 0; i--) {
144
- xmlXPathObjectPtr obj = rxml_xpath_from_value(rb_ary_shift(value));
145
-
146
- if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) {
147
- for (j = 0; j < obj->nodesetval->nodeNr; j++) {
148
- xmlXPathNodeSetAdd(result->nodesetval, obj->nodesetval->nodeTab[j]);
149
- }
150
- }
151
- }
152
- break;
153
- }
154
- default:
155
- rb_raise(rb_eTypeError,
156
- "can't convert object of type %s to XPath object", rb_obj_classname(value)
157
- );
158
- }
159
-
160
- return result;
161
- }
162
-
163
- void rxml_init_xpath(void)
164
- {
165
- mXPath = rb_define_module_under(mXML, "XPath");
166
-
167
- /* 0: Undefined value. */
168
- rb_define_const(mXPath, "UNDEFINED", INT2NUM(XPATH_UNDEFINED));
169
- /* 1: A nodeset, will be wrapped by XPath Object. */
170
- rb_define_const(mXPath, "NODESET", INT2NUM(XPATH_NODESET));
171
- /* 2: A boolean value. */
172
- rb_define_const(mXPath, "BOOLEAN", INT2NUM(XPATH_BOOLEAN));
173
- /* 3: A numeric value. */
174
- rb_define_const(mXPath, "NUMBER", INT2NUM(XPATH_NUMBER));
175
- /* 4: A string value. */
176
- rb_define_const(mXPath, "STRING", INT2NUM(XPATH_STRING));
177
- /* 5: An xpointer point */
178
- rb_define_const(mXPath, "POINT", INT2NUM(XPATH_POINT));
179
- /* 6: An xpointer range */
180
- rb_define_const(mXPath, "RANGE", INT2NUM(XPATH_RANGE));
181
- /* 7: An xpointer location set */
182
- rb_define_const(mXPath, "LOCATIONSET", INT2NUM(XPATH_LOCATIONSET));
183
- /* 8: XPath user type */
184
- rb_define_const(mXPath, "USERS", INT2NUM(XPATH_USERS));
185
- /* 9: An XSLT value tree, non modifiable */
186
- rb_define_const(mXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE));
187
- }
1
+ /*
2
+ * Document-class: LibXML::XML::XPath
3
+ *
4
+ * The XML::XPath module is used to query XML documents. It is
5
+ * usually accessed via the XML::Document#find or
6
+ * XML::Node#find methods. For example:
7
+ *
8
+ * document.find('/foo', namespaces) -> XML::XPath::Object
9
+ *
10
+ * The optional namespaces parameter can be a string, array or
11
+ * hash table.
12
+ *
13
+ * document.find('/foo', 'xlink:http://www.w3.org/1999/xlink')
14
+ * document.find('/foo', ['xlink:http://www.w3.org/1999/xlink',
15
+ * 'xi:http://www.w3.org/2001/XInclude')
16
+ * document.find('/foo', 'xlink' => 'http://www.w3.org/1999/xlink',
17
+ * 'xi' => 'http://www.w3.org/2001/XInclude')
18
+ *
19
+ *
20
+ * === Working With Default Namespaces
21
+ *
22
+ * Finding namespaced elements and attributes can be tricky.
23
+ * Lets work through an example of a document with a default
24
+ * namespace:
25
+ *
26
+ * <?xml version="1.0" encoding="utf-8"?>
27
+ * <feed xmlns="http://www.w3.org/2005/Atom">
28
+ * <title type="text">Phil Bogle's Contacts</title>
29
+ * </feed>
30
+ *
31
+ * To find nodes you must define the atom namespace for
32
+ * libxml. One way to do this is:
33
+ *
34
+ * node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
35
+ *
36
+ * Alternatively, you can register the default namespace like this:
37
+ *
38
+ * doc.root.namespaces.default_prefix = 'atom'
39
+ * node = doc.find('atom:title')
40
+ *
41
+ * === More Complex Namespace Examples
42
+ *
43
+ * Lets work through some more complex examples using the
44
+ * following xml document:
45
+ *
46
+ * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
47
+ * <soap:Body>
48
+ * <getManufacturerNamesResponse xmlns="http://services.somewhere.com">
49
+ * <IDAndNameList xmlns="http://services.somewhere.com">
50
+ * <ns1:IdAndName xmlns:ns1="http://domain.somewhere.com"/>
51
+ * </IDAndNameList>
52
+ * </getManufacturerNamesResponse>
53
+ * </soap:Body>
54
+ * </soap:Envelope>
55
+ *
56
+ * # Since the soap namespace is defined on the root
57
+ * # node we can directly use it.
58
+ * doc.find('/soap:Envelope')
59
+ *
60
+ * # Since the ns1 namespace is not defined on the root node
61
+ * # we have to first register it with the xpath engine.
62
+ * doc.find('//ns1:IdAndName',
63
+ * 'ns1:http://domain.somewhere.com')
64
+ *
65
+ * # Since the getManufacturerNamesResponse element uses a default
66
+ * # namespace we first have to give it a prefix and register
67
+ * # it with the xpath engine.
68
+ * doc.find('//ns:getManufacturerNamesResponse',
69
+ * 'ns:http://services.somewhere.com')
70
+ *
71
+ * # Here is an example showing a complex namespace aware
72
+ * # xpath expression.
73
+ * doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName',
74
+ * ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com'])
75
+ */
76
+
77
+
78
+ #include "ruby_libxml.h"
79
+
80
+ VALUE mXPath;
81
+
82
+ VALUE
83
+ rxml_xpath_to_value(xmlXPathContextPtr xctxt, xmlXPathObjectPtr xobject) {
84
+ VALUE result;
85
+ int type;
86
+
87
+ if (xobject == NULL) {
88
+ /* xmlLastError is different than xctxt->lastError. Use
89
+ xmlLastError since it has the message set while xctxt->lastError
90
+ does not. */
91
+ xmlErrorPtr xerror = xmlGetLastError();
92
+ rxml_raise(xerror);
93
+ }
94
+
95
+ switch (type = xobject->type) {
96
+ case XPATH_NODESET:
97
+ result = rxml_xpath_object_wrap(xctxt->doc, xobject);
98
+ break;
99
+ case XPATH_BOOLEAN:
100
+ result = (xobject->boolval != 0) ? Qtrue : Qfalse;
101
+ xmlXPathFreeObject(xobject);
102
+ break;
103
+ case XPATH_NUMBER:
104
+ result = rb_float_new(xobject->floatval);
105
+ xmlXPathFreeObject(xobject);
106
+ break;
107
+ case XPATH_STRING:
108
+ result = rxml_new_cstr(xobject->stringval, xctxt->doc->encoding);
109
+ xmlXPathFreeObject(xobject);
110
+ break;
111
+ default:
112
+ xmlXPathFreeObject(xobject);
113
+ rb_raise(rb_eTypeError,
114
+ "can't convert XPath object of type %d to Ruby value", type
115
+ );
116
+ }
117
+
118
+ return result;
119
+ }
120
+
121
+ xmlXPathObjectPtr
122
+ rxml_xpath_from_value(VALUE value) {
123
+ xmlXPathObjectPtr result = NULL;
124
+
125
+ switch (TYPE(value)) {
126
+ case T_TRUE:
127
+ case T_FALSE:
128
+ result = xmlXPathNewBoolean(RTEST(value));
129
+ break;
130
+ case T_FIXNUM:
131
+ case T_FLOAT:
132
+ result = xmlXPathNewFloat(NUM2DBL(value));
133
+ break;
134
+ case T_STRING:
135
+ result = xmlXPathWrapString(xmlStrdup((const xmlChar *)StringValuePtr(value)));
136
+ break;
137
+ case T_NIL:
138
+ result = xmlXPathNewNodeSet(NULL);
139
+ break;
140
+ case T_ARRAY: {
141
+ long i, j;
142
+ result = xmlXPathNewNodeSet(NULL);
143
+
144
+ for (i = RARRAY_LEN(value); i > 0; i--) {
145
+ xmlXPathObjectPtr obj = rxml_xpath_from_value(rb_ary_shift(value));
146
+
147
+ if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) {
148
+ for (j = 0; j < obj->nodesetval->nodeNr; j++) {
149
+ xmlXPathNodeSetAdd(result->nodesetval, obj->nodesetval->nodeTab[j]);
150
+ }
151
+ }
152
+ }
153
+ break;
154
+ }
155
+ default:
156
+ rb_raise(rb_eTypeError,
157
+ "can't convert object of type %s to XPath object", rb_obj_classname(value)
158
+ );
159
+ }
160
+
161
+ return result;
162
+ }
163
+
164
+ void rxml_init_xpath(void)
165
+ {
166
+ mXPath = rb_define_module_under(mXML, "XPath");
167
+
168
+ /* 0: Undefined value. */
169
+ rb_define_const(mXPath, "UNDEFINED", INT2NUM(XPATH_UNDEFINED));
170
+ /* 1: A nodeset, will be wrapped by XPath Object. */
171
+ rb_define_const(mXPath, "NODESET", INT2NUM(XPATH_NODESET));
172
+ /* 2: A boolean value. */
173
+ rb_define_const(mXPath, "BOOLEAN", INT2NUM(XPATH_BOOLEAN));
174
+ /* 3: A numeric value. */
175
+ rb_define_const(mXPath, "NUMBER", INT2NUM(XPATH_NUMBER));
176
+ /* 4: A string value. */
177
+ rb_define_const(mXPath, "STRING", INT2NUM(XPATH_STRING));
178
+ /* 5: An xpointer point */
179
+ rb_define_const(mXPath, "POINT", INT2NUM(XPATH_POINT));
180
+ /* 6: An xpointer range */
181
+ rb_define_const(mXPath, "RANGE", INT2NUM(XPATH_RANGE));
182
+ /* 7: An xpointer location set */
183
+ rb_define_const(mXPath, "LOCATIONSET", INT2NUM(XPATH_LOCATIONSET));
184
+ /* 8: XPath user type */
185
+ rb_define_const(mXPath, "USERS", INT2NUM(XPATH_USERS));
186
+ /* 9: An XSLT value tree, non modifiable */
187
+ rb_define_const(mXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE));
188
+ }