libxml-ruby 2.0.9 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +25 -0
- data/Rakefile +1 -1
- data/ext/libxml/ruby_libxml.h +0 -26
- data/ext/libxml/ruby_xml_attr.c +26 -43
- data/ext/libxml/ruby_xml_attr_decl.c +1 -17
- data/ext/libxml/ruby_xml_namespace.c +6 -22
- data/ext/libxml/ruby_xml_namespace.h +1 -1
- data/ext/libxml/ruby_xml_namespaces.c +5 -5
- data/ext/libxml/ruby_xml_node.c +1 -2
- data/ext/libxml/ruby_xml_parser_context.c +1 -1
- data/ext/libxml/ruby_xml_reader.c +24 -2
- data/ext/libxml/ruby_xml_version.h +4 -4
- data/ext/libxml/ruby_xml_xpath.c +82 -0
- data/ext/libxml/ruby_xml_xpath.h +3 -0
- data/ext/libxml/ruby_xml_xpath_context.c +25 -41
- data/ext/libxml/ruby_xml_xpath_object.c +3 -4
- data/libxml-ruby.gemspec +1 -0
- data/test/tc_attr.rb +31 -29
- data/test/tc_attributes.rb +9 -1
- data/test/tc_parser_context.rb +17 -1
- data/test/tc_reader.rb +25 -4
- metadata +5 -5
data/HISTORY
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
= Release History
|
2
2
|
|
3
|
+
== 2.1.0 / 2011-07-31 Charlie Savage
|
4
|
+
|
5
|
+
* Ruby 1.9.3 compatability (Charlie Savage).
|
6
|
+
|
7
|
+
* Added XPath expression <-> Ruby value conversion methods (Jens Wille).
|
8
|
+
|
9
|
+
* Extracted rxml_xpath_to_value from rxml_xpath_context_find (Jens Wille).
|
10
|
+
|
11
|
+
* Adapted rxml_xpath_from_value from Gregoire Lejeune's ruby-xslt
|
12
|
+
library, see https://github.com/glejeune/ruby-xslt (Jens Wille).
|
13
|
+
|
14
|
+
* Allow calling #find on nodes returned from Reader (Charlie Savage).
|
15
|
+
|
16
|
+
* Change document handling in XPath::Context to address segmentation fault on
|
17
|
+
Ruby Enterprise Edition (Charlie Savage).
|
18
|
+
|
19
|
+
* Update gemspec file to work directly with bundler thereby allowing git
|
20
|
+
repository to be used as gem (Charlie Savage).
|
21
|
+
|
22
|
+
* Support gem buld (Charlie Savage).
|
23
|
+
|
24
|
+
* Simplify memory management of attributes namespaces to fix
|
25
|
+
segmentation faults that occurred when using Ruby 1.9.3 (Charlie Savage).
|
26
|
+
|
27
|
+
|
3
28
|
== 2.0.8 / 2011-06-23 Charlie Savage
|
4
29
|
|
5
30
|
* Add in 2 new HTML Parser constants - NODEFDTD and NOIMPLIED.
|
data/Rakefile
CHANGED
@@ -4,7 +4,6 @@ require "rubygems"
|
|
4
4
|
require "rake/extensiontask"
|
5
5
|
require "rake/testtask"
|
6
6
|
require "rubygems/package_task"
|
7
|
-
##require 'hanna/rdoctask'
|
8
7
|
require "rdoc/task"
|
9
8
|
require "grancher/task"
|
10
9
|
require "yaml"
|
@@ -40,6 +39,7 @@ if RUBY_PLATFORM.match(/win32|mingw32/)
|
|
40
39
|
win_spec = spec.clone
|
41
40
|
win_spec.platform = Gem::Platform::CURRENT
|
42
41
|
win_spec.files += binaries.to_a
|
42
|
+
win_spec.instance_variable_set(:@cache_file, nil)
|
43
43
|
|
44
44
|
# Unset extensions
|
45
45
|
win_spec.extensions = nil
|
data/ext/libxml/ruby_libxml.h
CHANGED
@@ -16,37 +16,11 @@
|
|
16
16
|
#include <libxml/xmlreader.h>
|
17
17
|
#include <libxml/c14n.h>
|
18
18
|
|
19
|
-
/* Needed for Ruby 1.8.5 */
|
20
|
-
#ifndef RARRAY_LEN
|
21
|
-
#define RARRAY_LEN(s) (RARRAY(s)->len)
|
22
|
-
#endif
|
23
|
-
|
24
|
-
/* Needed for Ruby 1.8.5 */
|
25
|
-
#ifndef RARRAY_PTR
|
26
|
-
#define RARRAY_PTR(s) (RARRAY(s)->ptr)
|
27
|
-
#endif
|
28
|
-
|
29
|
-
/* Needed for Ruby 1.8.5 */
|
30
|
-
#ifndef RSTRING_LEN
|
31
|
-
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
32
|
-
#endif
|
33
|
-
|
34
|
-
/* Needed for Ruby 1.8.5 */
|
35
|
-
#ifndef RSTRING_PTR
|
36
|
-
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
37
|
-
#endif
|
38
|
-
|
39
19
|
/* Needed prior to Ruby 1.9.1 */
|
40
20
|
#ifndef RHASH_TBL
|
41
21
|
#define RHASH_TBL(s) (RHASH(s)->tbl)
|
42
22
|
#endif
|
43
23
|
|
44
|
-
// Not in Ruby 1.9
|
45
|
-
#ifndef GetWriteFile
|
46
|
-
#define GetWriteFile(fp) rb_io_stdio_file(fp)
|
47
|
-
#define OpenFile rb_io_t
|
48
|
-
#endif
|
49
|
-
|
50
24
|
// Encoding support added in Ruby 1.9.*
|
51
25
|
#ifdef HAVE_RUBY_ENCODING_H
|
52
26
|
#include <ruby/encoding.h>
|
data/ext/libxml/ruby_xml_attr.c
CHANGED
@@ -16,57 +16,38 @@
|
|
16
16
|
* attribute.remove!
|
17
17
|
*/
|
18
18
|
|
19
|
+
/* Attributes are owned and freed by their nodes. Thus, its easier for the
|
20
|
+
ruby bindings to not manage attribute memory management. This does mean
|
21
|
+
that accessing a particular attribute multiple times will return multiple
|
22
|
+
different ruby objects. Since we are not using free or xnode->_private
|
23
|
+
this works out fine. Previous versions of the bindings had a one to
|
24
|
+
one mapping between ruby object and xml attribute, but that could
|
25
|
+
result in segfaults because the ruby object could be gc'ed. In theory
|
26
|
+
the mark method on the parent node could prevent that, but if an
|
27
|
+
attribute is returned using an xpath statement then the node would
|
28
|
+
never by surfaced to ruby and the mark method never called. */
|
29
|
+
|
19
30
|
#include "ruby_libxml.h"
|
20
31
|
#include "ruby_xml_attr.h"
|
21
32
|
|
22
33
|
VALUE cXMLAttr;
|
23
34
|
|
24
|
-
void rxml_attr_free(xmlAttrPtr xattr)
|
25
|
-
{
|
26
|
-
if (!xattr)
|
27
|
-
return;
|
28
|
-
|
29
|
-
xattr->_private = NULL;
|
30
|
-
|
31
|
-
if (xattr->parent == NULL && xattr->doc == NULL)
|
32
|
-
{
|
33
|
-
xmlFreeProp(xattr);
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
35
|
void rxml_attr_mark(xmlAttrPtr xattr)
|
38
36
|
{
|
39
37
|
/* This can happen if Ruby does a GC run after creating the
|
40
38
|
new attribute but before initializing it. */
|
41
|
-
if (xattr
|
42
|
-
|
43
|
-
|
44
|
-
if (xattr->_private == NULL)
|
45
|
-
{
|
46
|
-
rb_warning("XmlAttr is not bound! (%s:%d)", __FILE__, __LINE__);
|
47
|
-
return;
|
48
|
-
}
|
49
|
-
|
50
|
-
rxml_node_mark((xmlNodePtr) xattr);
|
39
|
+
if (xattr != NULL)
|
40
|
+
rxml_node_mark((xmlNodePtr) xattr);
|
51
41
|
}
|
52
42
|
|
53
43
|
VALUE rxml_attr_wrap(xmlAttrPtr xattr)
|
54
44
|
{
|
55
|
-
|
56
|
-
|
57
|
-
/* Check if the node is already wrapped. */
|
58
|
-
if (xattr->_private != NULL)
|
59
|
-
return (VALUE) xattr->_private;
|
60
|
-
|
61
|
-
result = Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, rxml_attr_free, xattr);
|
62
|
-
xattr->_private = (void*) result;
|
63
|
-
|
64
|
-
return result;
|
45
|
+
return Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, NULL, xattr);
|
65
46
|
}
|
66
47
|
|
67
48
|
static VALUE rxml_attr_alloc(VALUE klass)
|
68
49
|
{
|
69
|
-
return Data_Wrap_Struct(klass, rxml_attr_mark,
|
50
|
+
return Data_Wrap_Struct(klass, rxml_attr_mark, NULL, NULL);
|
70
51
|
}
|
71
52
|
|
72
53
|
/*
|
@@ -116,7 +97,6 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
|
|
116
97
|
if (!xattr)
|
117
98
|
rb_raise(rb_eRuntimeError, "Could not create attribute.");
|
118
99
|
|
119
|
-
xattr->_private = (void *) self;
|
120
100
|
DATA_PTR( self) = xattr;
|
121
101
|
return self;
|
122
102
|
}
|
@@ -231,7 +211,7 @@ static VALUE rxml_attr_ns_get(VALUE self)
|
|
231
211
|
if (xattr->ns == NULL)
|
232
212
|
return Qnil;
|
233
213
|
else
|
234
|
-
return rxml_namespace_wrap(xattr->ns
|
214
|
+
return rxml_namespace_wrap(xattr->ns);
|
235
215
|
}
|
236
216
|
|
237
217
|
/*
|
@@ -268,21 +248,24 @@ static VALUE rxml_attr_prev_get(VALUE self)
|
|
268
248
|
|
269
249
|
/*
|
270
250
|
* call-seq:
|
271
|
-
*
|
251
|
+
* attr.remove! -> nil
|
272
252
|
*
|
273
|
-
* Removes this attribute from it's parent.
|
253
|
+
* Removes this attribute from it's parent. Note
|
254
|
+
* the attribute and its content is freed and can
|
255
|
+
* no longer be used. If you try to use it you
|
256
|
+
* will get a segmentation fault.
|
274
257
|
*/
|
275
258
|
static VALUE rxml_attr_remove_ex(VALUE self)
|
276
259
|
{
|
277
260
|
xmlAttrPtr xattr;
|
278
261
|
Data_Get_Struct(self, xmlAttr, xattr);
|
262
|
+
xmlRemoveProp(xattr);
|
279
263
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
xmlUnlinkNode((xmlNodePtr) xattr);
|
264
|
+
RDATA(self)->data = NULL;
|
265
|
+
RDATA(self)->dfree = NULL;
|
266
|
+
RDATA(self)->dmark = NULL;
|
284
267
|
|
285
|
-
return Qnil
|
268
|
+
return Qnil;
|
286
269
|
}
|
287
270
|
|
288
271
|
/*
|
@@ -15,28 +15,12 @@ VALUE cXMLAttrDecl;
|
|
15
15
|
|
16
16
|
void rxml_attr_decl_mark(xmlAttributePtr xattr)
|
17
17
|
{
|
18
|
-
if (xattr->_private == NULL)
|
19
|
-
{
|
20
|
-
rb_warning("AttrDecl is not bound! (%s:%d)", __FILE__, __LINE__);
|
21
|
-
return;
|
22
|
-
}
|
23
|
-
|
24
18
|
rxml_node_mark((xmlNodePtr) xattr);
|
25
19
|
}
|
26
20
|
|
27
21
|
VALUE rxml_attr_decl_wrap(xmlAttributePtr xattr)
|
28
22
|
{
|
29
|
-
|
30
|
-
|
31
|
-
// This node is already wrapped
|
32
|
-
if (xattr->_private != NULL)
|
33
|
-
return (VALUE) xattr->_private;
|
34
|
-
|
35
|
-
result = Data_Wrap_Struct(cXMLAttrDecl, rxml_attr_decl_mark, NULL, xattr);
|
36
|
-
|
37
|
-
xattr->_private = (void*) result;
|
38
|
-
|
39
|
-
return result;
|
23
|
+
return Data_Wrap_Struct(cXMLAttrDecl, rxml_attr_decl_mark, NULL, xattr);
|
40
24
|
}
|
41
25
|
|
42
26
|
/*
|
@@ -21,32 +21,17 @@ VALUE cXMLNamespace;
|
|
21
21
|
* assert_nil(node.namespaces.namespace)
|
22
22
|
*/
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
xns->_private = NULL;
|
27
|
-
}
|
24
|
+
/* Namespaces are owned and freed by their nodes. Thus, its easier for the
|
25
|
+
ruby bindings to not manage attribute memory management. */
|
28
26
|
|
29
27
|
static VALUE rxml_namespace_alloc(VALUE klass)
|
30
28
|
{
|
31
|
-
return Data_Wrap_Struct(klass, NULL,
|
29
|
+
return Data_Wrap_Struct(klass, NULL, NULL, NULL);
|
32
30
|
}
|
33
31
|
|
34
|
-
VALUE rxml_namespace_wrap(xmlNsPtr xns
|
32
|
+
VALUE rxml_namespace_wrap(xmlNsPtr xns)
|
35
33
|
{
|
36
|
-
|
37
|
-
{
|
38
|
-
return (VALUE)xns->_private;
|
39
|
-
}
|
40
|
-
else
|
41
|
-
{
|
42
|
-
VALUE ns;
|
43
|
-
if (freeFunc == NULL)
|
44
|
-
freeFunc = (RUBY_DATA_FUNC)rxml_namespace_free;
|
45
|
-
|
46
|
-
ns = Data_Wrap_Struct(cXMLNamespace, NULL, freeFunc, xns);
|
47
|
-
xns->_private = (void*)ns;
|
48
|
-
return ns;
|
49
|
-
}
|
34
|
+
return Data_Wrap_Struct(cXMLNamespace, NULL, NULL, xns);
|
50
35
|
}
|
51
36
|
|
52
37
|
static VALUE rxml_namespace_string(xmlNsPtr xns, const char* buffer)
|
@@ -84,7 +69,6 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
|
|
84
69
|
if (!xns)
|
85
70
|
rxml_raise(&xmlLastError);
|
86
71
|
|
87
|
-
xns->_private = (void*)self;
|
88
72
|
DATA_PTR(self) = xns;
|
89
73
|
return self;
|
90
74
|
}
|
@@ -163,7 +147,7 @@ static VALUE rxml_namespace_next(VALUE self)
|
|
163
147
|
if (xns == NULL || xns->next == NULL)
|
164
148
|
return (Qnil);
|
165
149
|
else
|
166
|
-
return
|
150
|
+
return rxml_namespace_wrap(xns->next);
|
167
151
|
}
|
168
152
|
|
169
153
|
void rxml_init_namespace(void)
|
@@ -90,7 +90,7 @@ static VALUE rxml_namespaces_definitions(VALUE self)
|
|
90
90
|
|
91
91
|
while (xns)
|
92
92
|
{
|
93
|
-
VALUE anamespace = rxml_namespace_wrap(xns
|
93
|
+
VALUE anamespace = rxml_namespace_wrap(xns);
|
94
94
|
rb_ary_push(arr, anamespace);
|
95
95
|
xns = xns->next;
|
96
96
|
}
|
@@ -126,7 +126,7 @@ static VALUE rxml_namespaces_each(VALUE self)
|
|
126
126
|
|
127
127
|
for (xns = nsList; *xns != NULL; xns++)
|
128
128
|
{
|
129
|
-
VALUE ns = rxml_namespace_wrap(*xns
|
129
|
+
VALUE ns = rxml_namespace_wrap(*xns);
|
130
130
|
rb_yield(ns);
|
131
131
|
}
|
132
132
|
xmlFree(nsList);
|
@@ -161,7 +161,7 @@ static VALUE rxml_namespaces_find_by_href(VALUE self, VALUE href)
|
|
161
161
|
|
162
162
|
xns = xmlSearchNsByHref(xnode->doc, xnode, (xmlChar*) StringValuePtr(href));
|
163
163
|
if (xns)
|
164
|
-
return rxml_namespace_wrap(xns
|
164
|
+
return rxml_namespace_wrap(xns);
|
165
165
|
else
|
166
166
|
return Qnil;
|
167
167
|
}
|
@@ -200,7 +200,7 @@ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix)
|
|
200
200
|
|
201
201
|
xns = xmlSearchNs(xnode->doc, xnode, xprefix);
|
202
202
|
if (xns)
|
203
|
-
return rxml_namespace_wrap(xns
|
203
|
+
return rxml_namespace_wrap(xns);
|
204
204
|
else
|
205
205
|
return Qnil;
|
206
206
|
}
|
@@ -224,7 +224,7 @@ static VALUE rxml_namespaces_namespace_get(VALUE self)
|
|
224
224
|
Data_Get_Struct(self, xmlNode, xnode);
|
225
225
|
|
226
226
|
if (xnode->ns)
|
227
|
-
return rxml_namespace_wrap(xnode->ns
|
227
|
+
return rxml_namespace_wrap(xnode->ns);
|
228
228
|
else
|
229
229
|
return Qnil;
|
230
230
|
}
|
data/ext/libxml/ruby_xml_node.c
CHANGED
@@ -508,8 +508,7 @@ static VALUE rxml_node_doc(VALUE self)
|
|
508
508
|
else if (xdoc->_private)
|
509
509
|
return (VALUE) xdoc->_private;
|
510
510
|
else
|
511
|
-
|
512
|
-
rb_raise(eXMLError, "Document is not accessible to Ruby (hint - did you call Reader#expand?)");
|
511
|
+
return (Qnil);
|
513
512
|
}
|
514
513
|
|
515
514
|
/*
|
@@ -350,7 +350,7 @@ static VALUE rxml_parser_context_encoding_set(VALUE self, VALUE encoding)
|
|
350
350
|
xmlCharEncodingHandlerPtr hdlr = xmlFindCharEncodingHandler(xencoding);
|
351
351
|
|
352
352
|
if (!hdlr)
|
353
|
-
rb_raise(
|
353
|
+
rb_raise(rb_eArgError, "Unknown encoding: %i", NUM2INT(encoding));
|
354
354
|
|
355
355
|
Data_Get_Struct(self, xmlParserCtxt, ctxt);
|
356
356
|
result = xmlSwitchToEncoding(ctxt, hdlr);
|
@@ -42,6 +42,11 @@
|
|
42
42
|
*
|
43
43
|
* For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlreader.html.*/
|
44
44
|
|
45
|
+
|
46
|
+
/* NOTE - We need to wrap the readers document to support Reader.read.node.find('/').
|
47
|
+
To do this we need to use xmlTextReaderCurrentDoc which means we have to free the
|
48
|
+
document ourselves. Annoying... */
|
49
|
+
|
45
50
|
VALUE cXMLReader;
|
46
51
|
|
47
52
|
static ID BASE_URI_SYMBOL;
|
@@ -54,11 +59,20 @@ static void rxml_reader_free(xmlTextReaderPtr xreader)
|
|
54
59
|
xmlFreeTextReader(xreader);
|
55
60
|
}
|
56
61
|
|
62
|
+
static void rxml_reader_mark(xmlTextReaderPtr xreader)
|
63
|
+
{
|
64
|
+
xmlDocPtr xdoc = xmlTextReaderCurrentDoc(xreader);
|
65
|
+
|
66
|
+
if (xdoc && xdoc->_private)
|
67
|
+
rb_gc_mark((VALUE) xdoc->_private);
|
68
|
+
}
|
69
|
+
|
57
70
|
static VALUE rxml_reader_wrap(xmlTextReaderPtr xreader)
|
58
71
|
{
|
59
72
|
return Data_Wrap_Struct(cXMLReader, NULL, rxml_reader_free, xreader);
|
60
73
|
}
|
61
74
|
|
75
|
+
|
62
76
|
static xmlTextReaderPtr rxml_text_reader_get(VALUE obj)
|
63
77
|
{
|
64
78
|
xmlTextReaderPtr xreader;
|
@@ -414,7 +428,7 @@ static VALUE rxml_reader_normalization(VALUE self)
|
|
414
428
|
|
415
429
|
/*
|
416
430
|
* call-seq:
|
417
|
-
* reader.read ->
|
431
|
+
* reader.read -> nil|true|false
|
418
432
|
*
|
419
433
|
* Causes the reader to move to the next node in the stream, exposing its properties.
|
420
434
|
*
|
@@ -873,7 +887,15 @@ static VALUE rxml_reader_lookup_namespace(VALUE self, VALUE prefix)
|
|
873
887
|
static VALUE rxml_reader_expand(VALUE self)
|
874
888
|
{
|
875
889
|
xmlTextReaderPtr xreader = rxml_text_reader_get(self);
|
876
|
-
xmlNodePtr xnode =
|
890
|
+
xmlNodePtr xnode = NULL;
|
891
|
+
|
892
|
+
/* At this point we need to wrap the reader's document as explained above. */
|
893
|
+
rxml_document_wrap(xmlTextReaderCurrentDoc(xreader));
|
894
|
+
|
895
|
+
/* And now hook in a mark function */
|
896
|
+
RDATA(self)->dmark = (RUBY_DATA_FUNC)rxml_reader_mark;
|
897
|
+
|
898
|
+
xnode = xmlTextReaderExpand(xreader);
|
877
899
|
|
878
900
|
if (!xnode)
|
879
901
|
{
|
@@ -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.0
|
5
|
-
#define RUBY_LIBXML_VERNUM
|
4
|
+
#define RUBY_LIBXML_VERSION "2.1.0"
|
5
|
+
#define RUBY_LIBXML_VERNUM 210
|
6
6
|
#define RUBY_LIBXML_VER_MAJ 2
|
7
|
-
#define RUBY_LIBXML_VER_MIN
|
8
|
-
#define RUBY_LIBXML_VER_MIC
|
7
|
+
#define RUBY_LIBXML_VER_MIN 1
|
8
|
+
#define RUBY_LIBXML_VER_MIC 0
|
9
9
|
#define RUBY_LIBXML_VER_PATCH 0
|
data/ext/libxml/ruby_xml_xpath.c
CHANGED
@@ -78,6 +78,88 @@
|
|
78
78
|
|
79
79
|
VALUE mXPath;
|
80
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_str_new2((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
|
+
|
81
163
|
void rxml_init_xpath(void)
|
82
164
|
{
|
83
165
|
mXPath = rb_define_module_under(mXML, "XPath");
|
data/ext/libxml/ruby_xml_xpath.h
CHANGED
@@ -26,16 +26,20 @@
|
|
26
26
|
|
27
27
|
VALUE cXMLXPathContext;
|
28
28
|
|
29
|
-
static ID DOC_ATTRIBUTE;
|
30
|
-
|
31
29
|
static void rxml_xpath_context_free(xmlXPathContextPtr ctxt)
|
32
30
|
{
|
33
31
|
xmlXPathFreeContext(ctxt);
|
34
32
|
}
|
35
33
|
|
34
|
+
static void rxml_xpath_context_mark(xmlXPathContextPtr ctxt)
|
35
|
+
{
|
36
|
+
if (ctxt->doc->_private)
|
37
|
+
rb_gc_mark((VALUE) ctxt->doc->_private);
|
38
|
+
}
|
39
|
+
|
36
40
|
static VALUE rxml_xpath_context_alloc(VALUE klass)
|
37
41
|
{
|
38
|
-
return Data_Wrap_Struct(cXMLXPathContext,
|
42
|
+
return Data_Wrap_Struct(cXMLXPathContext, rxml_xpath_context_mark, rxml_xpath_context_free, NULL);
|
39
43
|
}
|
40
44
|
|
41
45
|
/* call-seq:
|
@@ -72,12 +76,25 @@ static VALUE rxml_xpath_context_initialize(VALUE self, VALUE node)
|
|
72
76
|
Data_Get_Struct(document, xmlDoc, xdoc);
|
73
77
|
DATA_PTR(self) = xmlXPathNewContext(xdoc);
|
74
78
|
|
75
|
-
/* Save the doc as an attribute, this will expose it to Ruby's GC. */
|
76
|
-
rb_ivar_set(self, DOC_ATTRIBUTE, document);
|
77
|
-
|
78
79
|
return self;
|
79
80
|
}
|
80
81
|
|
82
|
+
/*
|
83
|
+
* call-seq:
|
84
|
+
* context.doc -> document
|
85
|
+
*
|
86
|
+
* Obtain the XML::Document this node belongs to.
|
87
|
+
*/
|
88
|
+
static VALUE rxml_xpath_context_doc(VALUE self)
|
89
|
+
{
|
90
|
+
xmlDocPtr xdoc = NULL;
|
91
|
+
xmlXPathContextPtr ctxt;
|
92
|
+
Data_Get_Struct(self, xmlXPathContext, ctxt);
|
93
|
+
|
94
|
+
xdoc = ctxt->doc;
|
95
|
+
return rxml_document_wrap(xdoc);
|
96
|
+
}
|
97
|
+
|
81
98
|
/*
|
82
99
|
* call-seq:
|
83
100
|
* context.register_namespace(prefix, uri) -> (true|false)
|
@@ -264,7 +281,6 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
|
|
264
281
|
xmlXPathContextPtr xctxt;
|
265
282
|
xmlXPathObjectPtr xobject;
|
266
283
|
xmlXPathCompExprPtr xcompexpr;
|
267
|
-
VALUE result;
|
268
284
|
|
269
285
|
Data_Get_Struct(self, xmlXPathContext, xctxt);
|
270
286
|
|
@@ -284,37 +300,7 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
|
|
284
300
|
"Argument should be an intance of a String or XPath::Expression");
|
285
301
|
}
|
286
302
|
|
287
|
-
|
288
|
-
{
|
289
|
-
/* xmlLastError is different than xctxt->lastError. Use
|
290
|
-
xmlLastError since it has the message set while xctxt->lastError
|
291
|
-
does not. */
|
292
|
-
xmlErrorPtr xerror = xmlGetLastError();
|
293
|
-
rxml_raise(xerror);
|
294
|
-
}
|
295
|
-
|
296
|
-
switch (xobject->type)
|
297
|
-
{
|
298
|
-
case XPATH_NODESET:
|
299
|
-
result = rxml_xpath_object_wrap(xctxt->doc, xobject);
|
300
|
-
break;
|
301
|
-
case XPATH_BOOLEAN:
|
302
|
-
result = (xobject->boolval != 0) ? Qtrue : Qfalse;
|
303
|
-
xmlXPathFreeObject(xobject);
|
304
|
-
break;
|
305
|
-
case XPATH_NUMBER:
|
306
|
-
result = rb_float_new(xobject->floatval);
|
307
|
-
xmlXPathFreeObject(xobject);
|
308
|
-
break;
|
309
|
-
case XPATH_STRING:
|
310
|
-
result = rxml_str_new2((const char*)xobject->stringval, xctxt->doc->encoding);
|
311
|
-
xmlXPathFreeObject(xobject);
|
312
|
-
break;
|
313
|
-
default:
|
314
|
-
result = Qnil;
|
315
|
-
xmlXPathFreeObject(xobject);
|
316
|
-
}
|
317
|
-
return result;
|
303
|
+
return rxml_xpath_to_value(xctxt, xobject);
|
318
304
|
}
|
319
305
|
|
320
306
|
#if LIBXML_VERSION >= 20626
|
@@ -370,11 +356,9 @@ rxml_xpath_context_disable_cache(VALUE self)
|
|
370
356
|
|
371
357
|
void rxml_init_xpath_context(void)
|
372
358
|
{
|
373
|
-
DOC_ATTRIBUTE = rb_intern("@doc");
|
374
|
-
|
375
359
|
cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
|
376
360
|
rb_define_alloc_func(cXMLXPathContext, rxml_xpath_context_alloc);
|
377
|
-
|
361
|
+
rb_define_method(cXMLXPathContext, "doc", rxml_xpath_context_doc, 0);
|
378
362
|
rb_define_method(cXMLXPathContext, "initialize", rxml_xpath_context_initialize, 1);
|
379
363
|
rb_define_method(cXMLXPathContext, "register_namespaces", rxml_xpath_context_register_namespaces, 1);
|
380
364
|
rb_define_method(cXMLXPathContext, "register_namespaces_from_node", rxml_xpath_context_register_namespaces_from_node, 1);
|
@@ -45,7 +45,6 @@ static void rxml_xpath_object_free(rxml_xpath_object *rxpop)
|
|
45
45
|
/* Custom free function for copied namespace nodes */
|
46
46
|
static void rxml_namespace_xpath_free(xmlNsPtr xns)
|
47
47
|
{
|
48
|
-
xns->_private = NULL;
|
49
48
|
xmlFreeNs(xns);
|
50
49
|
}
|
51
50
|
|
@@ -82,7 +81,8 @@ VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
|
|
82
81
|
|
83
82
|
/* Specify a custom free function here since by default
|
84
83
|
namespace nodes will not be freed */
|
85
|
-
ns = rxml_namespace_wrap((xmlNsPtr)xnode
|
84
|
+
ns = rxml_namespace_wrap((xmlNsPtr)xnode);
|
85
|
+
RDATA(ns)->dfree = (RUBY_DATA_FUNC)rxml_namespace_xpath_free;
|
86
86
|
rb_ary_push(rxpop->nsnodes, ns);
|
87
87
|
}
|
88
88
|
}
|
@@ -93,7 +93,6 @@ VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
|
|
93
93
|
|
94
94
|
static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int apos)
|
95
95
|
{
|
96
|
-
|
97
96
|
if (apos < 0)
|
98
97
|
apos = xpop->nodesetval->nodeNr + apos;
|
99
98
|
|
@@ -106,7 +105,7 @@ static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int apos)
|
|
106
105
|
return rxml_attr_wrap((xmlAttrPtr) xpop->nodesetval->nodeTab[apos]);
|
107
106
|
break;
|
108
107
|
case XML_NAMESPACE_DECL:
|
109
|
-
return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[apos]
|
108
|
+
return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[apos]);
|
110
109
|
break;
|
111
110
|
default:
|
112
111
|
return rxml_node_wrap(xpop->nodesetval->nodeTab[apos]);
|
data/libxml-ruby.gemspec
CHANGED
data/test/tc_attr.rb
CHANGED
@@ -27,6 +27,7 @@ class AttrNodeTest < Test::Unit::TestCase
|
|
27
27
|
|
28
28
|
def teardown
|
29
29
|
@doc = nil
|
30
|
+
GC.start
|
30
31
|
end
|
31
32
|
|
32
33
|
def city_member
|
@@ -37,117 +38,118 @@ class AttrNodeTest < Test::Unit::TestCase
|
|
37
38
|
assert_not_nil(@doc)
|
38
39
|
assert_equal(XML::Encoding::NONE, @doc.encoding)
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
def test_types
|
42
43
|
attribute = city_member.attributes.get_attribute('name')
|
43
44
|
assert_instance_of(XML::Attr, attribute)
|
44
45
|
assert_equal('attribute', attribute.node_type_name)
|
45
46
|
end
|
46
|
-
|
47
|
+
|
47
48
|
def test_name
|
48
49
|
attribute = city_member.attributes.get_attribute('name')
|
49
50
|
assert_equal('name', attribute.name)
|
50
51
|
assert_equal(Encoding::ASCII_8BIT, attribute.name.encoding) if defined?(Encoding)
|
51
|
-
|
52
|
+
|
52
53
|
attribute = city_member.attributes.get_attribute('href')
|
53
54
|
assert_equal('href', attribute.name)
|
54
55
|
assert_equal('xlink', attribute.ns.prefix)
|
55
56
|
assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href)
|
56
|
-
|
57
|
+
|
57
58
|
attribute = city_member.attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href')
|
58
59
|
assert_equal('href', attribute.name)
|
59
60
|
assert_equal('xlink', attribute.ns.prefix)
|
60
61
|
assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href)
|
61
62
|
end
|
62
|
-
|
63
|
+
|
63
64
|
def test_value
|
64
65
|
attribute = city_member.attributes.get_attribute('name')
|
65
66
|
assert_equal('Cambridge', attribute.value)
|
66
67
|
assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
|
67
|
-
|
68
|
+
|
68
69
|
attribute = city_member.attributes.get_attribute('href')
|
69
70
|
assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attribute.value)
|
70
71
|
end
|
71
|
-
|
72
|
+
|
72
73
|
def test_set_value
|
73
74
|
attribute = city_member.attributes.get_attribute('name')
|
74
75
|
attribute.value = 'London'
|
75
76
|
assert_equal('London', attribute.value)
|
76
77
|
assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
|
77
|
-
|
78
|
+
|
78
79
|
attribute = city_member.attributes.get_attribute('href')
|
79
80
|
attribute.value = 'http://i.have.changed'
|
80
81
|
assert_equal('http://i.have.changed', attribute.value)
|
81
82
|
assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
|
82
83
|
end
|
83
|
-
|
84
|
+
|
84
85
|
def test_set_nil
|
85
86
|
attribute = city_member.attributes.get_attribute('name')
|
86
87
|
assert_raise(TypeError) do
|
87
88
|
attribute.value = nil
|
88
89
|
end
|
89
90
|
end
|
90
|
-
|
91
|
+
|
91
92
|
def test_create
|
92
93
|
attributes = city_member.attributes
|
93
94
|
assert_equal(5, attributes.length)
|
94
|
-
|
95
|
+
|
95
96
|
attr = XML::Attr.new(city_member, 'size', '50,000')
|
96
97
|
assert_instance_of(XML::Attr, attr)
|
97
|
-
|
98
|
+
|
98
99
|
attributes = city_member.attributes
|
99
100
|
assert_equal(6, attributes.length)
|
100
|
-
|
101
|
+
|
101
102
|
assert_equal(attributes['size'], '50,000')
|
102
103
|
end
|
103
|
-
|
104
|
+
|
104
105
|
def test_create_on_node
|
105
106
|
attributes = city_member.attributes
|
106
107
|
assert_equal(5, attributes.length)
|
107
|
-
|
108
|
+
|
108
109
|
attributes['country'] = 'England'
|
109
|
-
|
110
|
+
|
110
111
|
attributes = city_member.attributes
|
111
112
|
assert_equal(6, attributes.length)
|
112
|
-
|
113
|
+
|
113
114
|
assert_equal(attributes['country'], 'England')
|
114
115
|
end
|
115
|
-
|
116
|
+
|
116
117
|
def test_create_ns
|
117
118
|
assert_equal(5, city_member.attributes.length)
|
118
|
-
|
119
|
+
|
119
120
|
ns = XML::Namespace.new(city_member, 'my_namepace', 'http://www.mynamespace.com')
|
120
121
|
attr = XML::Attr.new(city_member, 'rating', 'rocks', ns)
|
121
122
|
assert_instance_of(XML::Attr, attr)
|
122
123
|
assert_equal('rating', attr.name)
|
123
124
|
assert_equal('rocks', attr.value)
|
124
|
-
|
125
|
+
|
125
126
|
attributes = city_member.attributes
|
126
127
|
assert_equal(6, attributes.length)
|
127
|
-
|
128
|
+
|
128
129
|
assert_equal('rocks', city_member['rating'])
|
129
130
|
end
|
130
131
|
|
131
132
|
def test_remove
|
132
133
|
attributes = city_member.attributes
|
133
134
|
assert_equal(5, attributes.length)
|
134
|
-
|
135
|
+
|
135
136
|
attribute = attributes.get_attribute('name')
|
136
137
|
assert_not_nil(attribute.parent)
|
137
138
|
assert(attribute.parent?)
|
138
|
-
|
139
|
+
|
139
140
|
attribute.remove!
|
140
141
|
assert_equal(4, attributes.length)
|
141
|
-
|
142
|
-
|
142
|
+
|
143
|
+
attribute = attributes.get_attribute('name')
|
144
|
+
assert_nil(attribute)
|
143
145
|
end
|
144
|
-
|
146
|
+
|
145
147
|
def test_first
|
146
148
|
attribute = city_member.attributes.first
|
147
149
|
assert_instance_of(XML::Attr, attribute)
|
148
150
|
assert_equal('name', attribute.name)
|
149
151
|
assert_equal('Cambridge', attribute.value)
|
150
|
-
|
152
|
+
|
151
153
|
attribute = attribute.next
|
152
154
|
assert_instance_of(XML::Attr, attribute)
|
153
155
|
assert_equal('type', attribute.name)
|
@@ -157,7 +159,7 @@ class AttrNodeTest < Test::Unit::TestCase
|
|
157
159
|
assert_instance_of(XML::Attr, attribute)
|
158
160
|
assert_equal('title', attribute.name)
|
159
161
|
assert_equal('Trinity Lane', attribute.value)
|
160
|
-
|
162
|
+
|
161
163
|
attribute = attribute.next
|
162
164
|
assert_instance_of(XML::Attr, attribute)
|
163
165
|
assert_equal('href', attribute.name)
|
@@ -167,7 +169,7 @@ class AttrNodeTest < Test::Unit::TestCase
|
|
167
169
|
assert_instance_of(XML::Attr, attribute)
|
168
170
|
assert_equal('remoteSchema', attribute.name)
|
169
171
|
assert_equal("city.xsd#xpointer(//complexType[@name='RoadType'])", attribute.value)
|
170
|
-
|
172
|
+
|
171
173
|
attribute = attribute.next
|
172
174
|
assert_nil(attribute)
|
173
175
|
end
|
data/test/tc_attributes.rb
CHANGED
@@ -6,7 +6,7 @@ require 'test/unit'
|
|
6
6
|
class AttributesTest < Test::Unit::TestCase
|
7
7
|
def setup
|
8
8
|
xp = XML::Parser.string(<<-EOS)
|
9
|
-
<CityModel
|
9
|
+
<CityModel name="value"
|
10
10
|
xmlns="http://www.opengis.net/examples"
|
11
11
|
xmlns:city="http://www.opengis.net/examples"
|
12
12
|
xmlns:gml="http://www.opengis.net/gml"
|
@@ -90,6 +90,14 @@ class AttributesTest < Test::Unit::TestCase
|
|
90
90
|
assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attributes[:href])
|
91
91
|
end
|
92
92
|
|
93
|
+
def test_get_values_gc
|
94
|
+
# There used to be a bug caused by accessing an
|
95
|
+
# attribute over and over and over again.
|
96
|
+
20000.times do
|
97
|
+
@doc.root.attributes["key"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
93
101
|
def test_set_values
|
94
102
|
city_member[:name] = 'London'
|
95
103
|
assert_equal('London', city_member[:name])
|
data/test/tc_parser_context.rb
CHANGED
@@ -34,6 +34,22 @@ class TestParserContext < Test::Unit::TestCase
|
|
34
34
|
assert_equal(XML::Encoding::ISO_8859_1, context.encoding)
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_invalid_encoding
|
38
|
+
# UTF8
|
39
|
+
xml = <<-EOS
|
40
|
+
<bands>
|
41
|
+
<metal>m\303\266tley_cr\303\274e</metal>
|
42
|
+
</bands>
|
43
|
+
EOS
|
44
|
+
|
45
|
+
context = XML::Parser::Context.string(xml)
|
46
|
+
|
47
|
+
error = assert_raise(ArgumentError) do
|
48
|
+
context.encoding = -999
|
49
|
+
end
|
50
|
+
assert_equal("Unknown encoding: -999", error.to_s)
|
51
|
+
end
|
52
|
+
|
37
53
|
def test_base_uri
|
38
54
|
# UTF8
|
39
55
|
xml = <<-EOS
|
@@ -51,7 +67,7 @@ class TestParserContext < Test::Unit::TestCase
|
|
51
67
|
|
52
68
|
def test_string_empty
|
53
69
|
error = assert_raise(TypeError) do
|
54
|
-
|
70
|
+
XML::Parser::Context.string(nil)
|
55
71
|
end
|
56
72
|
assert_equal("wrong argument type nil (expected String)", error.to_s)
|
57
73
|
|
data/test/tc_reader.rb
CHANGED
@@ -171,12 +171,33 @@ class TestReader < Test::Unit::TestCase
|
|
171
171
|
node = reader.expand
|
172
172
|
assert_equal('feed', node.name)
|
173
173
|
assert_equal(::Encoding::UTF_8, node.name.encoding) if defined?(::Encoding)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_expand_doc
|
177
|
+
reader = XML::Reader.file(XML_FILE)
|
178
|
+
reader.read.to_s
|
179
|
+
reader.read
|
180
|
+
|
181
|
+
# Read a node
|
182
|
+
node = reader.expand
|
174
183
|
|
175
184
|
# Try to access the document
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
185
|
+
assert_not_nil(node.doc)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_expand_find
|
189
|
+
reader = XML::Reader.file(XML_FILE)
|
190
|
+
reader.read.to_s
|
191
|
+
reader.read
|
192
|
+
|
193
|
+
# Read first node which
|
194
|
+
node = reader.expand
|
195
|
+
assert_equal('feed', node.name)
|
196
|
+
|
197
|
+
# Search for entries
|
198
|
+
entries = node.find('atom:entry', 'atom:http://www.w3.org/2005/Atom')
|
199
|
+
|
200
|
+
assert_equal(1, entries.length)
|
180
201
|
end
|
181
202
|
|
182
203
|
def test_mode
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libxml-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 2.0.9
|
10
|
+
version: 2.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ross Bamform
|
@@ -20,7 +20,7 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2011-
|
23
|
+
date: 2011-07-31 00:00:00 Z
|
24
24
|
dependencies: []
|
25
25
|
|
26
26
|
description: " The Libxml-Ruby project provides Ruby language bindings for the GNOME\n Libxml2 XML toolkit. It is free software, released under the MIT License.\n Libxml-ruby's primary advantage over REXML is performance - if speed\n is your need, these are good libraries to consider, as demonstrated\n by the informal benchmark below.\n"
|
@@ -222,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
222
222
|
requirements: []
|
223
223
|
|
224
224
|
rubyforge_project:
|
225
|
-
rubygems_version: 1.
|
225
|
+
rubygems_version: 1.8.6
|
226
226
|
signing_key:
|
227
227
|
specification_version: 3
|
228
228
|
summary: Ruby Bindings for LibXML2
|