nokogiri 1.6.7.2-x64-mingw32 → 1.6.8.rc1-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +12 -9
- data/CHANGELOG.ja.rdoc +18 -0
- data/CHANGELOG.rdoc +12 -7
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +1 -1
- data/Manifest.txt +6 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/bin/nokogiri +2 -2
- data/dependencies.yml +1 -1
- data/ext/nokogiri/extconf.rb +3 -3
- data/ext/nokogiri/nokogiri.c +0 -7
- data/ext/nokogiri/nokogiri.h +1 -34
- data/ext/nokogiri/xml_document.c +2 -4
- data/ext/nokogiri/xml_namespace.c +56 -17
- data/ext/nokogiri/xml_node.c +12 -36
- data/ext/nokogiri/xml_node_set.c +169 -143
- data/ext/nokogiri/xml_node_set.h +3 -4
- data/ext/nokogiri/xml_sax_parser.c +2 -5
- data/ext/nokogiri/xml_syntax_error.c +0 -4
- data/ext/nokogiri/xml_syntax_error.h +0 -1
- data/ext/nokogiri/xml_xpath_context.c +9 -18
- data/lib/nokogiri.rb +3 -0
- data/lib/nokogiri/2.0/nokogiri.so +0 -0
- data/lib/nokogiri/2.1/nokogiri.so +0 -0
- data/lib/nokogiri/2.2/nokogiri.so +0 -0
- data/lib/nokogiri/css/parser.rb +8 -2
- data/lib/nokogiri/css/parser.y +7 -2
- data/lib/nokogiri/version.rb +1 -1
- data/lib/nokogiri/xml/document.rb +7 -1
- data/lib/nokogiri/xml/dtd.rb +4 -4
- data/lib/nokogiri/xml/node.rb +2 -2
- data/test/css/test_parser.rb +7 -1
- data/test/files/GH_1042.html +18 -0
- data/test/files/namespace_pressure_test.xml +1684 -0
- data/test/files/tlm.html +2 -1
- data/test/html/sax/test_parser.rb +2 -2
- data/test/html/test_document.rb +18 -8
- data/test/html/test_document_encoding.rb +46 -54
- data/test/html/test_document_fragment.rb +21 -22
- data/test/html/test_node.rb +16 -0
- data/test/html/test_node_encoding.rb +12 -14
- data/test/namespaces/test_namespaces_in_parsed_doc.rb +14 -0
- data/test/test_reader.rb +19 -0
- data/test/test_xslt_transforms.rb +5 -3
- data/test/xml/sax/test_parser.rb +36 -39
- data/test/xml/test_document.rb +7 -2
- data/test/xml/test_document_encoding.rb +14 -16
- data/test/xml/test_dtd_encoding.rb +0 -2
- data/test/xml/test_node_encoding.rb +78 -80
- data/test/xml/test_reader_encoding.rb +100 -102
- data/test/xslt/test_exception_handling.rb +1 -1
- metadata +11 -7
data/ext/nokogiri/xml_node.c
CHANGED
@@ -234,15 +234,7 @@ ok:
|
|
234
234
|
* reparent the actual reparentee, so we reparent a duplicate.
|
235
235
|
*/
|
236
236
|
nokogiri_root_node(reparentee);
|
237
|
-
|
238
|
-
xmlResetLastError();
|
239
|
-
xmlSetStructuredErrorFunc((void *)rb_iv_get(DOC_RUBY_OBJECT(pivot->doc), "@errors"), Nokogiri_error_array_pusher);
|
240
|
-
|
241
|
-
reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1) ;
|
242
|
-
|
243
|
-
xmlSetStructuredErrorFunc(NULL, NULL);
|
244
|
-
|
245
|
-
if (! reparentee) {
|
237
|
+
if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
|
246
238
|
rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
|
247
239
|
}
|
248
240
|
}
|
@@ -481,13 +473,7 @@ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
|
|
481
473
|
|
482
474
|
Data_Get_Struct(self, xmlNode, node);
|
483
475
|
|
484
|
-
xmlResetLastError();
|
485
|
-
xmlSetStructuredErrorFunc(NULL, Nokogiri_error_silencer);
|
486
|
-
|
487
476
|
dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
|
488
|
-
|
489
|
-
xmlSetStructuredErrorFunc(NULL, NULL);
|
490
|
-
|
491
477
|
if(dup == NULL) return Qnil;
|
492
478
|
|
493
479
|
nokogiri_root_node(dup);
|
@@ -778,19 +764,11 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
|
778
764
|
*
|
779
765
|
* Set the +property+ to +value+
|
780
766
|
*/
|
781
|
-
static VALUE set(VALUE
|
767
|
+
static VALUE set(VALUE self, VALUE property, VALUE value)
|
782
768
|
{
|
783
769
|
xmlNodePtr node, cur;
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
Data_Get_Struct(node_rb, xmlNode, node);
|
788
|
-
|
789
|
-
if (node->type != XML_ELEMENT_NODE) {
|
790
|
-
return(Qnil); // TODO: would raising an exception be more appropriate?
|
791
|
-
}
|
792
|
-
|
793
|
-
property_name = (xmlChar *)StringValuePtr(property_name_rb);
|
770
|
+
xmlAttrPtr prop;
|
771
|
+
Data_Get_Struct(self, xmlNode, node);
|
794
772
|
|
795
773
|
/* If a matching attribute node already exists, then xmlSetProp will destroy
|
796
774
|
* the existing node's children. However, if Nokogiri has a node object
|
@@ -798,9 +776,11 @@ static VALUE set(VALUE node_rb, VALUE property_name_rb, VALUE property_value_rb)
|
|
798
776
|
*
|
799
777
|
* We can avoid this by unlinking these nodes first.
|
800
778
|
*/
|
801
|
-
|
802
|
-
|
803
|
-
|
779
|
+
if (node->type != XML_ELEMENT_NODE)
|
780
|
+
return(Qnil);
|
781
|
+
prop = xmlHasProp(node, (xmlChar *)StringValuePtr(property));
|
782
|
+
if (prop && prop->children) {
|
783
|
+
for (cur = prop->children; cur; cur = cur->next) {
|
804
784
|
if (cur->_private) {
|
805
785
|
nokogiri_root_node(cur);
|
806
786
|
xmlUnlinkNode(cur);
|
@@ -808,14 +788,10 @@ static VALUE set(VALUE node_rb, VALUE property_name_rb, VALUE property_value_rb)
|
|
808
788
|
}
|
809
789
|
}
|
810
790
|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
xmlSetProp(node, property_name, (xmlChar *)StringValuePtr(property_value_rb));
|
815
|
-
|
816
|
-
xmlSetStructuredErrorFunc(NULL, NULL);
|
791
|
+
xmlSetProp(node, (xmlChar *)StringValuePtr(property),
|
792
|
+
(xmlChar *)StringValuePtr(value));
|
817
793
|
|
818
|
-
return
|
794
|
+
return value;
|
819
795
|
}
|
820
796
|
|
821
797
|
/*
|
data/ext/nokogiri/xml_node_set.c
CHANGED
@@ -1,62 +1,42 @@
|
|
1
1
|
#include <xml_node_set.h>
|
2
|
+
#include <xml_namespace.h>
|
2
3
|
#include <libxml/xpathInternals.h>
|
3
4
|
|
4
5
|
static ID decorate ;
|
6
|
+
static void xpath_node_set_del(xmlNodeSetPtr cur, xmlNodePtr val);
|
5
7
|
|
6
|
-
|
8
|
+
|
9
|
+
static void Check_Node_Set_Node_Type(VALUE node)
|
7
10
|
{
|
8
|
-
if (
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
xmlFree(ns);
|
13
|
-
return ST_CONTINUE;
|
11
|
+
if (!(rb_obj_is_kind_of(node, cNokogiriXmlNode) ||
|
12
|
+
rb_obj_is_kind_of(node, cNokogiriXmlNamespace))) {
|
13
|
+
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
14
|
+
}
|
14
15
|
}
|
15
16
|
|
16
|
-
|
17
|
+
|
18
|
+
static void deallocate(xmlNodeSetPtr node_set)
|
17
19
|
{
|
18
20
|
/*
|
19
|
-
* xmlXPathFreeNodeSet() contains an implicit assumption that it is being
|
20
|
-
* called before any of its pointed-to nodes have been free()d. this
|
21
|
-
* assumption lies in the operation where it dereferences nodeTab pointers
|
22
|
-
* while searching for namespace nodes to free.
|
23
|
-
*
|
24
|
-
* however, since Ruby's GC mechanism cannot guarantee the strict order in
|
25
|
-
* which ruby objects will be GC'd, nodes may be garbage collected before a
|
26
|
-
* nodeset containing pointers to those nodes. (this is true regardless of
|
27
|
-
* how we declare dependencies between objects with rb_gc_mark().)
|
28
21
|
*
|
29
|
-
*
|
30
|
-
*
|
22
|
+
* since xpath queries return copies of the xmlNs structs,
|
23
|
+
* xmlXPathFreeNodeSet() frees those xmlNs structs that are in the
|
24
|
+
* NodeSet.
|
31
25
|
*
|
32
|
-
*
|
33
|
-
*
|
34
|
-
* well as the NodeSet, without using the official xmlXPathFreeNodeSet().
|
26
|
+
* this is bad if someone is still trying to use the Namespace object wrapped
|
27
|
+
* around the xmlNs, so we need to avoid that.
|
35
28
|
*
|
36
|
-
*
|
37
|
-
* single array, structs with different memory-ownership semantics. or more
|
38
|
-
* generally, a lesson about building an API in C/C++ that does not contain
|
39
|
-
* assumptions about the strict order in which memory will be released. hey,
|
40
|
-
* that sounds like a great idea for a blog post! get to it!
|
29
|
+
* here we reproduce xmlXPathFreeNodeSet() without the xmlNs logic.
|
41
30
|
*
|
42
|
-
*
|
31
|
+
* this doesn't cause a leak because Namespace objects that are in an XPath
|
32
|
+
* query NodeSet are given their own lifecycle in
|
33
|
+
* Nokogiri_wrap_xml_namespace().
|
43
34
|
*/
|
44
|
-
xmlNodeSetPtr node_set;
|
45
|
-
|
46
|
-
node_set = tuple->node_set;
|
47
|
-
|
48
|
-
if (!node_set)
|
49
|
-
return;
|
50
|
-
|
51
35
|
NOKOGIRI_DEBUG_START(node_set) ;
|
52
|
-
st_foreach(tuple->namespaces, dealloc_namespace, 0);
|
53
|
-
|
54
36
|
if (node_set->nodeTab != NULL)
|
55
37
|
xmlFree(node_set->nodeTab);
|
56
38
|
|
57
39
|
xmlFree(node_set);
|
58
|
-
st_free_table(tuple->namespaces);
|
59
|
-
free(tuple);
|
60
40
|
NOKOGIRI_DEBUG_END(node_set) ;
|
61
41
|
}
|
62
42
|
|
@@ -74,12 +54,12 @@ static VALUE allocate(VALUE klass)
|
|
74
54
|
*/
|
75
55
|
static VALUE duplicate(VALUE self)
|
76
56
|
{
|
77
|
-
|
57
|
+
xmlNodeSetPtr node_set;
|
78
58
|
xmlNodeSetPtr dupl;
|
79
59
|
|
80
|
-
Data_Get_Struct(self,
|
60
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
81
61
|
|
82
|
-
dupl = xmlXPathNodeSetMerge(NULL,
|
62
|
+
dupl = xmlXPathNodeSetMerge(NULL, node_set);
|
83
63
|
|
84
64
|
return Nokogiri_wrap_xml_node_set(dupl, rb_iv_get(self, "@document"));
|
85
65
|
}
|
@@ -92,10 +72,11 @@ static VALUE duplicate(VALUE self)
|
|
92
72
|
*/
|
93
73
|
static VALUE length(VALUE self)
|
94
74
|
{
|
95
|
-
|
96
|
-
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
75
|
+
xmlNodeSetPtr node_set;
|
97
76
|
|
98
|
-
|
77
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
78
|
+
|
79
|
+
return node_set ? INT2NUM(node_set->nodeNr) : INT2NUM(0);
|
99
80
|
}
|
100
81
|
|
101
82
|
/*
|
@@ -106,15 +87,16 @@ static VALUE length(VALUE self)
|
|
106
87
|
*/
|
107
88
|
static VALUE push(VALUE self, VALUE rb_node)
|
108
89
|
{
|
109
|
-
|
90
|
+
xmlNodeSetPtr node_set;
|
110
91
|
xmlNodePtr node;
|
111
92
|
|
112
|
-
|
113
|
-
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
93
|
+
Check_Node_Set_Node_Type(rb_node);
|
114
94
|
|
115
|
-
Data_Get_Struct(self,
|
95
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
116
96
|
Data_Get_Struct(rb_node, xmlNode, node);
|
117
|
-
|
97
|
+
|
98
|
+
xmlXPathNodeSetAdd(node_set, node);
|
99
|
+
|
118
100
|
return self;
|
119
101
|
}
|
120
102
|
|
@@ -128,29 +110,19 @@ static VALUE push(VALUE self, VALUE rb_node)
|
|
128
110
|
static VALUE
|
129
111
|
delete(VALUE self, VALUE rb_node)
|
130
112
|
{
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
for (i = 0; i < cur->nodeNr; i++)
|
145
|
-
if (cur->nodeTab[i] == node) break;
|
146
|
-
|
147
|
-
cur->nodeNr--;
|
148
|
-
for (;i < cur->nodeNr;i++)
|
149
|
-
cur->nodeTab[i] = cur->nodeTab[i + 1];
|
150
|
-
cur->nodeTab[cur->nodeNr] = NULL;
|
151
|
-
return rb_node;
|
152
|
-
}
|
153
|
-
return Qnil ;
|
113
|
+
xmlNodeSetPtr node_set;
|
114
|
+
xmlNodePtr node;
|
115
|
+
|
116
|
+
Check_Node_Set_Node_Type(rb_node);
|
117
|
+
|
118
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
119
|
+
Data_Get_Struct(rb_node, xmlNode, node);
|
120
|
+
|
121
|
+
if (xmlXPathNodeSetContains(node_set, node)) {
|
122
|
+
xpath_node_set_del(node_set, node);
|
123
|
+
return rb_node;
|
124
|
+
}
|
125
|
+
return Qnil ;
|
154
126
|
}
|
155
127
|
|
156
128
|
|
@@ -162,16 +134,16 @@ delete(VALUE self, VALUE rb_node)
|
|
162
134
|
*/
|
163
135
|
static VALUE intersection(VALUE self, VALUE rb_other)
|
164
136
|
{
|
165
|
-
|
137
|
+
xmlNodeSetPtr node_set, other ;
|
166
138
|
xmlNodeSetPtr intersection;
|
167
139
|
|
168
140
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
169
141
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
170
142
|
|
171
|
-
Data_Get_Struct(self,
|
172
|
-
Data_Get_Struct(rb_other,
|
143
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
144
|
+
Data_Get_Struct(rb_other, xmlNodeSet, other);
|
173
145
|
|
174
|
-
intersection = xmlXPathIntersection(
|
146
|
+
intersection = xmlXPathIntersection(node_set, other);
|
175
147
|
return Nokogiri_wrap_xml_node_set(intersection, rb_iv_get(self, "@document"));
|
176
148
|
}
|
177
149
|
|
@@ -184,16 +156,15 @@ static VALUE intersection(VALUE self, VALUE rb_other)
|
|
184
156
|
*/
|
185
157
|
static VALUE include_eh(VALUE self, VALUE rb_node)
|
186
158
|
{
|
187
|
-
|
159
|
+
xmlNodeSetPtr node_set;
|
188
160
|
xmlNodePtr node;
|
189
161
|
|
190
|
-
|
191
|
-
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
162
|
+
Check_Node_Set_Node_Type(rb_node);
|
192
163
|
|
193
|
-
Data_Get_Struct(self,
|
164
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
194
165
|
Data_Get_Struct(rb_node, xmlNode, node);
|
195
166
|
|
196
|
-
return (xmlXPathNodeSetContains(
|
167
|
+
return (xmlXPathNodeSetContains(node_set, node) ? Qtrue : Qfalse);
|
197
168
|
}
|
198
169
|
|
199
170
|
|
@@ -206,17 +177,17 @@ static VALUE include_eh(VALUE self, VALUE rb_node)
|
|
206
177
|
*/
|
207
178
|
static VALUE set_union(VALUE self, VALUE rb_other)
|
208
179
|
{
|
209
|
-
|
180
|
+
xmlNodeSetPtr node_set, other;
|
210
181
|
xmlNodeSetPtr new;
|
211
182
|
|
212
183
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
213
184
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
214
185
|
|
215
|
-
Data_Get_Struct(self,
|
216
|
-
Data_Get_Struct(rb_other,
|
186
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
187
|
+
Data_Get_Struct(rb_other, xmlNodeSet, other);
|
217
188
|
|
218
|
-
new = xmlXPathNodeSetMerge(NULL,
|
219
|
-
new = xmlXPathNodeSetMerge(new, other
|
189
|
+
new = xmlXPathNodeSetMerge(NULL, node_set);
|
190
|
+
new = xmlXPathNodeSetMerge(new, other);
|
220
191
|
|
221
192
|
return Nokogiri_wrap_xml_node_set(new, rb_iv_get(self, "@document"));
|
222
193
|
}
|
@@ -230,19 +201,19 @@ static VALUE set_union(VALUE self, VALUE rb_other)
|
|
230
201
|
*/
|
231
202
|
static VALUE minus(VALUE self, VALUE rb_other)
|
232
203
|
{
|
233
|
-
|
204
|
+
xmlNodeSetPtr node_set, other;
|
234
205
|
xmlNodeSetPtr new;
|
235
206
|
int j ;
|
236
207
|
|
237
208
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
238
209
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
239
210
|
|
240
|
-
Data_Get_Struct(self,
|
241
|
-
Data_Get_Struct(rb_other,
|
211
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
212
|
+
Data_Get_Struct(rb_other, xmlNodeSet, other);
|
242
213
|
|
243
|
-
new = xmlXPathNodeSetMerge(NULL,
|
244
|
-
for (j = 0 ; j < other->
|
245
|
-
|
214
|
+
new = xmlXPathNodeSetMerge(NULL, node_set);
|
215
|
+
for (j = 0 ; j < other->nodeNr ; ++j) {
|
216
|
+
xpath_node_set_del(new, other->nodeTab[j]);
|
246
217
|
}
|
247
218
|
|
248
219
|
return Nokogiri_wrap_xml_node_set(new, rb_iv_get(self, "@document"));
|
@@ -252,31 +223,25 @@ static VALUE minus(VALUE self, VALUE rb_other)
|
|
252
223
|
static VALUE index_at(VALUE self, long offset)
|
253
224
|
{
|
254
225
|
xmlNodeSetPtr node_set;
|
255
|
-
nokogiriNodeSetTuple *tuple;
|
256
226
|
|
257
|
-
Data_Get_Struct(self,
|
258
|
-
node_set = tuple->node_set;
|
227
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
259
228
|
|
260
|
-
if (offset >= node_set->nodeNr || abs((int)offset) > node_set->nodeNr)
|
229
|
+
if (offset >= node_set->nodeNr || abs((int)offset) > node_set->nodeNr) {
|
261
230
|
return Qnil;
|
231
|
+
}
|
262
232
|
|
263
|
-
if (offset < 0)
|
264
|
-
offset += node_set->nodeNr;
|
233
|
+
if (offset < 0) { offset += node_set->nodeNr ; }
|
265
234
|
|
266
|
-
|
267
|
-
return Nokogiri_wrap_xml_namespace2(rb_iv_get(self, "@document"), (xmlNsPtr)(node_set->nodeTab[offset]));
|
268
|
-
return Nokogiri_wrap_xml_node(Qnil, node_set->nodeTab[offset]);
|
235
|
+
return Nokogiri_wrap_xml_node_set_node(node_set->nodeTab[offset], self);
|
269
236
|
}
|
270
237
|
|
271
238
|
static VALUE subseq(VALUE self, long beg, long len)
|
272
239
|
{
|
273
240
|
long j;
|
274
|
-
nokogiriNodeSetTuple *tuple;
|
275
241
|
xmlNodeSetPtr node_set;
|
276
242
|
xmlNodeSetPtr new_set ;
|
277
243
|
|
278
|
-
Data_Get_Struct(self,
|
279
|
-
node_set = tuple->node_set;
|
244
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
280
245
|
|
281
246
|
if (beg > node_set->nodeNr) return Qnil ;
|
282
247
|
if (beg < 0 || len < 0) return Qnil ;
|
@@ -312,9 +277,8 @@ static VALUE slice(int argc, VALUE *argv, VALUE self)
|
|
312
277
|
VALUE arg ;
|
313
278
|
long beg, len ;
|
314
279
|
xmlNodeSetPtr node_set;
|
315
|
-
|
316
|
-
Data_Get_Struct(self,
|
317
|
-
node_set = tuple->node_set;
|
280
|
+
|
281
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
318
282
|
|
319
283
|
if (argc == 2) {
|
320
284
|
beg = NUM2LONG(argv[0]);
|
@@ -333,7 +297,7 @@ static VALUE slice(int argc, VALUE *argv, VALUE self)
|
|
333
297
|
if (FIXNUM_P(arg)) {
|
334
298
|
return index_at(self, FIX2LONG(arg));
|
335
299
|
}
|
336
|
-
|
300
|
+
|
337
301
|
/* if arg is Range */
|
338
302
|
switch (rb_range_beg_len(arg, &beg, &len, (long)node_set->nodeNr, 0)) {
|
339
303
|
case Qfalse:
|
@@ -356,26 +320,25 @@ static VALUE slice(int argc, VALUE *argv, VALUE self)
|
|
356
320
|
*/
|
357
321
|
static VALUE to_array(VALUE self, VALUE rb_node)
|
358
322
|
{
|
359
|
-
xmlNodeSetPtr
|
323
|
+
xmlNodeSetPtr node_set ;
|
360
324
|
VALUE *elts;
|
361
325
|
VALUE list;
|
362
326
|
int i;
|
363
|
-
nokogiriNodeSetTuple *tuple;
|
364
327
|
|
365
|
-
Data_Get_Struct(self,
|
366
|
-
set = tuple->node_set;
|
328
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
367
329
|
|
368
|
-
elts = calloc((size_t)
|
369
|
-
for(i = 0; i <
|
370
|
-
|
371
|
-
|
372
|
-
else
|
373
|
-
elts[i] = Nokogiri_wrap_xml_node(Qnil, set->nodeTab[i]);
|
330
|
+
elts = (VALUE *)calloc((size_t)(node_set->nodeNr), sizeof(VALUE));
|
331
|
+
for(i = 0; i < node_set->nodeNr; i++) {
|
332
|
+
elts[i] = Nokogiri_wrap_xml_node_set_node(node_set->nodeTab[i], self);
|
333
|
+
rb_gc_register_address(&elts[i]);
|
374
334
|
}
|
375
335
|
|
376
|
-
list = rb_ary_new4((long)
|
336
|
+
list = rb_ary_new4((long)node_set->nodeNr, elts);
|
377
337
|
|
378
|
-
|
338
|
+
for(i = 0; i < node_set->nodeNr; i++) {
|
339
|
+
rb_gc_unregister_address(&elts[i]);
|
340
|
+
}
|
341
|
+
free(elts);
|
379
342
|
|
380
343
|
return list;
|
381
344
|
}
|
@@ -390,13 +353,12 @@ static VALUE unlink_nodeset(VALUE self)
|
|
390
353
|
{
|
391
354
|
xmlNodeSetPtr node_set;
|
392
355
|
int j, nodeNr ;
|
393
|
-
nokogiriNodeSetTuple *tuple;
|
394
356
|
|
395
|
-
Data_Get_Struct(self,
|
396
|
-
|
357
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
358
|
+
|
397
359
|
nodeNr = node_set->nodeNr ;
|
398
360
|
for (j = 0 ; j < nodeNr ; j++) {
|
399
|
-
if (
|
361
|
+
if (! Nokogiri_namespace_eh(node_set->nodeTab[j])) {
|
400
362
|
VALUE node ;
|
401
363
|
xmlNodePtr node_ptr;
|
402
364
|
node = Nokogiri_wrap_xml_node(Qnil, node_set->nodeTab[j]);
|
@@ -408,39 +370,103 @@ static VALUE unlink_nodeset(VALUE self)
|
|
408
370
|
return self ;
|
409
371
|
}
|
410
372
|
|
373
|
+
|
374
|
+
static void reify_node_set_namespaces(VALUE self)
|
375
|
+
{
|
376
|
+
/*
|
377
|
+
* as mentioned in deallocate() above, xmlNs structs returned in an XPath
|
378
|
+
* NodeSet are duplicates, and we don't clean them up at deallocate() time.
|
379
|
+
*
|
380
|
+
* as a result, we need to make sure the Ruby manages this memory. we do this
|
381
|
+
* by forcing the creation of a Ruby object wrapped around the xmlNs.
|
382
|
+
*
|
383
|
+
* we also have to make sure that the NodeSet has a reference to the
|
384
|
+
* Namespace object, otherwise GC will kick in and the Namespace won't be
|
385
|
+
* marked.
|
386
|
+
*
|
387
|
+
* we *could* do this safely with *all* the nodes in the NodeSet, but we only
|
388
|
+
* *need* to do it for xmlNs structs, and so you get the code we have here.
|
389
|
+
*/
|
390
|
+
int j ;
|
391
|
+
xmlNodeSetPtr node_set ;
|
392
|
+
VALUE namespace_cache ;
|
393
|
+
|
394
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
395
|
+
|
396
|
+
namespace_cache = rb_iv_get(self, "@namespace_cache");
|
397
|
+
|
398
|
+
for (j = 0 ; j < node_set->nodeNr ; j++) {
|
399
|
+
if (Nokogiri_namespace_eh(node_set->nodeTab[j])) {
|
400
|
+
rb_ary_push(namespace_cache, Nokogiri_wrap_xml_node_set_node(node_set->nodeTab[j], self));
|
401
|
+
}
|
402
|
+
}
|
403
|
+
}
|
404
|
+
|
405
|
+
|
411
406
|
VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set, VALUE document)
|
412
407
|
{
|
413
408
|
VALUE new_set ;
|
414
|
-
int i;
|
415
|
-
xmlNodePtr cur;
|
416
|
-
xmlNsPtr ns;
|
417
|
-
nokogiriNodeSetTuple *tuple;
|
418
409
|
|
419
|
-
|
420
|
-
|
410
|
+
if (node_set == NULL) {
|
411
|
+
node_set = xmlXPathNodeSetCreate(NULL);
|
412
|
+
}
|
421
413
|
|
422
|
-
|
423
|
-
tuple->namespaces = st_init_numtable();
|
414
|
+
new_set = Data_Wrap_Struct(cNokogiriXmlNodeSet, 0, deallocate, node_set);
|
424
415
|
|
425
416
|
if (!NIL_P(document)) {
|
426
417
|
rb_iv_set(new_set, "@document", document);
|
427
418
|
rb_funcall(document, decorate, 1, new_set);
|
428
419
|
}
|
429
420
|
|
430
|
-
|
431
|
-
|
432
|
-
cur = node_set->nodeTab[i];
|
433
|
-
if (cur && cur->type == XML_NAMESPACE_DECL) {
|
434
|
-
ns = (xmlNsPtr)cur;
|
435
|
-
if (ns->next && ns->next->type != XML_NAMESPACE_DECL)
|
436
|
-
st_insert(tuple->namespaces, (st_data_t)cur, (st_data_t)0);
|
437
|
-
}
|
438
|
-
}
|
439
|
-
}
|
421
|
+
rb_iv_set(new_set, "@namespace_cache", rb_ary_new());
|
422
|
+
reify_node_set_namespaces(new_set);
|
440
423
|
|
441
424
|
return new_set ;
|
442
425
|
}
|
443
426
|
|
427
|
+
VALUE Nokogiri_wrap_xml_node_set_node(xmlNodePtr node, VALUE node_set)
|
428
|
+
{
|
429
|
+
xmlDocPtr document ;
|
430
|
+
|
431
|
+
if (Nokogiri_namespace_eh(node)) {
|
432
|
+
Data_Get_Struct(rb_iv_get(node_set, "@document"), xmlDoc, document);
|
433
|
+
return Nokogiri_wrap_xml_namespace(document, (xmlNsPtr)node);
|
434
|
+
} else {
|
435
|
+
return Nokogiri_wrap_xml_node(Qnil, node);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
|
440
|
+
static void xpath_node_set_del(xmlNodeSetPtr cur, xmlNodePtr val)
|
441
|
+
{
|
442
|
+
/*
|
443
|
+
* as mentioned a few times above, we do not want to free xmlNs structs
|
444
|
+
* outside of the Namespace lifecycle.
|
445
|
+
*
|
446
|
+
* xmlXPathNodeSetDel() frees xmlNs structs, and so here we reproduce that
|
447
|
+
* function with the xmlNs logic.
|
448
|
+
*/
|
449
|
+
int i;
|
450
|
+
|
451
|
+
if (cur == NULL) return;
|
452
|
+
if (val == NULL) return;
|
453
|
+
|
454
|
+
/*
|
455
|
+
* find node in nodeTab
|
456
|
+
*/
|
457
|
+
for (i = 0;i < cur->nodeNr;i++)
|
458
|
+
if (cur->nodeTab[i] == val) break;
|
459
|
+
|
460
|
+
if (i >= cur->nodeNr) { /* not found */
|
461
|
+
return;
|
462
|
+
}
|
463
|
+
cur->nodeNr--;
|
464
|
+
for (;i < cur->nodeNr;i++)
|
465
|
+
cur->nodeTab[i] = cur->nodeTab[i + 1];
|
466
|
+
cur->nodeTab[cur->nodeNr] = NULL;
|
467
|
+
}
|
468
|
+
|
469
|
+
|
444
470
|
VALUE cNokogiriXmlNodeSet ;
|
445
471
|
void init_xml_node_set(void)
|
446
472
|
{
|