libxml-ruby 2.7.0 → 2.9.0

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.
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
+ }