libxml-ruby 2.8.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.
- checksums.yaml +4 -4
- data/HISTORY +15 -0
- data/README.rdoc +7 -7
- data/Rakefile +80 -78
- data/ext/libxml/extconf.h +4 -0
- data/ext/libxml/extconf.rb +57 -116
- data/ext/libxml/libxml.c +4 -0
- data/ext/libxml/ruby_xml.c +977 -893
- data/ext/libxml/ruby_xml.h +20 -10
- data/ext/libxml/ruby_xml_attr.c +333 -333
- data/ext/libxml/ruby_xml_attr_decl.c +2 -2
- data/ext/libxml/ruby_xml_cbg.c +85 -85
- data/ext/libxml/ruby_xml_document.c +1133 -1147
- data/ext/libxml/ruby_xml_dtd.c +261 -268
- data/ext/libxml/ruby_xml_encoding.c +262 -260
- data/ext/libxml/ruby_xml_encoding.h +19 -19
- data/ext/libxml/ruby_xml_html_parser_context.c +337 -338
- data/ext/libxml/ruby_xml_input_cbg.c +191 -191
- data/ext/libxml/ruby_xml_io.c +52 -50
- data/ext/libxml/ruby_xml_namespace.c +2 -2
- data/ext/libxml/ruby_xml_node.c +1446 -1452
- data/ext/libxml/ruby_xml_parser_context.c +999 -1001
- data/ext/libxml/ruby_xml_reader.c +1226 -1228
- data/ext/libxml/ruby_xml_relaxng.c +110 -111
- data/ext/libxml/ruby_xml_sax2_handler.c +326 -328
- data/ext/libxml/ruby_xml_schema.c +300 -301
- data/ext/libxml/ruby_xml_version.h +3 -3
- data/ext/libxml/ruby_xml_writer.c +14 -15
- data/ext/libxml/ruby_xml_xpath.c +188 -188
- data/ext/libxml/ruby_xml_xpath_context.c +360 -361
- data/ext/libxml/ruby_xml_xpath_object.c +335 -335
- data/libxml-ruby.gemspec +47 -44
- data/test/tc_attr.rb +5 -7
- data/test/tc_attr_decl.rb +5 -6
- data/test/tc_attributes.rb +1 -2
- data/test/tc_canonicalize.rb +1 -2
- data/test/tc_deprecated_require.rb +1 -2
- data/test/tc_document.rb +4 -5
- data/test/tc_document_write.rb +2 -3
- data/test/tc_dtd.rb +4 -5
- data/test/tc_encoding.rb +126 -126
- data/test/tc_encoding_sax.rb +4 -3
- data/test/tc_error.rb +14 -15
- data/test/tc_html_parser.rb +15 -7
- data/test/tc_html_parser_context.rb +1 -2
- data/test/tc_namespace.rb +2 -3
- data/test/tc_namespaces.rb +5 -6
- data/test/tc_node.rb +2 -3
- data/test/tc_node_cdata.rb +2 -3
- data/test/tc_node_comment.rb +1 -2
- data/test/tc_node_copy.rb +1 -2
- data/test/tc_node_edit.rb +5 -7
- data/test/tc_node_pi.rb +1 -2
- data/test/tc_node_text.rb +2 -3
- data/test/tc_node_write.rb +2 -3
- data/test/tc_node_xlink.rb +1 -2
- data/test/tc_parser.rb +18 -24
- data/test/tc_parser_context.rb +6 -7
- data/test/tc_properties.rb +1 -2
- data/test/tc_reader.rb +9 -10
- data/test/tc_relaxng.rb +4 -5
- data/test/tc_sax_parser.rb +9 -10
- data/test/tc_schema.rb +4 -5
- data/test/tc_traversal.rb +1 -2
- data/test/tc_writer.rb +1 -2
- data/test/tc_xinclude.rb +1 -2
- data/test/tc_xml.rb +1 -2
- data/test/tc_xpath.rb +8 -9
- data/test/tc_xpath_context.rb +3 -4
- data/test/tc_xpath_expression.rb +3 -4
- data/test/tc_xpointer.rb +1 -3
- data/test/test_helper.rb +3 -1
- data/test/test_suite.rb +0 -1
- metadata +47 -11
- data/test/etc_doc_to_s.rb +0 -21
- data/test/ets_doc_file.rb +0 -17
- data/test/ets_doc_to_s.rb +0 -23
- data/test/ets_gpx.rb +0 -28
- data/test/ets_node_gc.rb +0 -23
- data/test/ets_test.xml +0 -2
- data/test/ets_tsr.rb +0 -11
@@ -1,9 +1,9 @@
|
|
1
1
|
/* Don't nuke this block! It is used for automatically updating the
|
2
2
|
* versions below. VERSION = string formatting, VERNUM = numbered
|
3
3
|
* version for inline testing: increment both or none at all.*/
|
4
|
-
#define RUBY_LIBXML_VERSION "2.
|
5
|
-
#define RUBY_LIBXML_VERNUM
|
4
|
+
#define RUBY_LIBXML_VERSION "2.9.0"
|
5
|
+
#define RUBY_LIBXML_VERNUM 290
|
6
6
|
#define RUBY_LIBXML_VER_MAJ 2
|
7
|
-
#define RUBY_LIBXML_VER_MIN
|
7
|
+
#define RUBY_LIBXML_VER_MIN 9
|
8
8
|
#define RUBY_LIBXML_VER_MIC 0
|
9
9
|
#define RUBY_LIBXML_VER_PATCH 0
|
@@ -257,7 +257,7 @@ static VALUE rxml_writer_flush(int argc, VALUE *argv, VALUE self)
|
|
257
257
|
VALUE content;
|
258
258
|
|
259
259
|
#ifdef HAVE_RUBY_ENCODING_H
|
260
|
-
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);
|
261
261
|
#else
|
262
262
|
content = rb_str_new(rwo->buffer->content, rwo->buffer->use);
|
263
263
|
#endif /* HAVE_RUBY_ENCODING_H */
|
@@ -280,20 +280,20 @@ static VALUE rxml_writer_flush(int argc, VALUE *argv, VALUE self)
|
|
280
280
|
*/
|
281
281
|
static VALUE rxml_writer_result(VALUE self)
|
282
282
|
{
|
283
|
-
VALUE ret;
|
284
|
-
rxml_writer_object *rwo;
|
283
|
+
VALUE ret = Qnil;
|
284
|
+
rxml_writer_object *rwo = rxml_textwriter_get(self);
|
285
|
+
int bytesWritten = xmlTextWriterFlush(rwo->writer);
|
285
286
|
|
286
|
-
|
287
|
-
rwo = rxml_textwriter_get(self);
|
288
|
-
if (-1 == (ret = xmlTextWriterFlush(rwo->writer))) {
|
287
|
+
if (bytesWritten == -1) {
|
289
288
|
rxml_raise(&xmlLastError);
|
290
289
|
}
|
290
|
+
|
291
291
|
switch (rwo->output_type) {
|
292
292
|
case RXMLW_OUTPUT_DOC:
|
293
293
|
ret = rwo->output;
|
294
294
|
break;
|
295
295
|
case RXMLW_OUTPUT_STRING:
|
296
|
-
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);
|
297
297
|
break;
|
298
298
|
case RXMLW_OUTPUT_IO:
|
299
299
|
case RXMLW_OUTPUT_NONE:
|
@@ -334,7 +334,8 @@ static VALUE numeric_rxml_writer_void(VALUE obj, int (*fn)(xmlTextWriterPtr))
|
|
334
334
|
static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_count, int (*fn)(ANYARGS), ...)
|
335
335
|
{
|
336
336
|
va_list ap;
|
337
|
-
|
337
|
+
size_t argc;
|
338
|
+
int ret = -1;
|
338
339
|
rxml_writer_object *rwo;
|
339
340
|
const xmlChar *argv[XMLWRITER_MAX_STRING_ARGS];
|
340
341
|
VALUE utf8[XMLWRITER_MAX_STRING_ARGS], orig[XMLWRITER_MAX_STRING_ARGS];
|
@@ -342,7 +343,6 @@ static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_
|
|
342
343
|
if (strings_count > XMLWRITER_MAX_STRING_ARGS) {
|
343
344
|
rb_bug("more arguments than expected");
|
344
345
|
}
|
345
|
-
ret = -1;
|
346
346
|
va_start(ap, fn);
|
347
347
|
rwo = rxml_textwriter_get(obj);
|
348
348
|
for (argc = 0; argc < strings_count; argc++) {
|
@@ -765,12 +765,11 @@ static VALUE rxml_writer_end_cdata(VALUE self)
|
|
765
765
|
static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
|
766
766
|
{
|
767
767
|
int ret;
|
768
|
-
VALUE options;
|
768
|
+
VALUE options = Qnil;
|
769
769
|
rxml_writer_object *rwo;
|
770
|
-
const
|
770
|
+
const xmlChar *xencoding = NULL;
|
771
|
+
const char *xstandalone = NULL;
|
771
772
|
|
772
|
-
options = Qnil;
|
773
|
-
xstandalone = xencoding = NULL;
|
774
773
|
rb_scan_args(argc, argv, "01", &options);
|
775
774
|
if (!NIL_P(options)) {
|
776
775
|
VALUE encoding, standalone;
|
@@ -778,7 +777,7 @@ static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
|
|
778
777
|
encoding = standalone = Qnil;
|
779
778
|
Check_Type(options, T_HASH);
|
780
779
|
encoding = rb_hash_aref(options, sEncoding);
|
781
|
-
xencoding = NIL_P(encoding) ? NULL : xmlGetCharEncodingName(NUM2INT(encoding));
|
780
|
+
xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
|
782
781
|
standalone = rb_hash_aref(options, sStandalone);
|
783
782
|
if (NIL_P(standalone)) {
|
784
783
|
xstandalone = NULL;
|
@@ -790,7 +789,7 @@ static VALUE rxml_writer_start_document(int argc, VALUE *argv, VALUE self)
|
|
790
789
|
#ifdef HAVE_RUBY_ENCODING_H
|
791
790
|
rwo->encoding = rxml_figure_encoding(xencoding);
|
792
791
|
#endif /* !HAVE_RUBY_ENCODING_H */
|
793
|
-
ret = xmlTextWriterStartDocument(rwo->writer, NULL, xencoding, xstandalone);
|
792
|
+
ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
|
794
793
|
|
795
794
|
return (-1 == ret ? Qfalse : Qtrue);
|
796
795
|
}
|
data/ext/libxml/ruby_xml_xpath.c
CHANGED
@@ -1,188 +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: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(
|
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
|
-
|
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
|
-
}
|
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
|
+
}
|