nokogiri 1.5.0-x86-mswin32-60 → 1.5.1.rc1-x86-mswin32-60
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.
- data/CHANGELOG.ja.rdoc +39 -12
- data/CHANGELOG.rdoc +28 -0
- data/C_CODING_STYLE.rdoc +27 -0
- data/Manifest.txt +4 -0
- data/README.rdoc +11 -7
- data/Rakefile +40 -25
- data/bin/nokogiri +10 -2
- data/ext/nokogiri/extconf.rb +9 -1
- data/ext/nokogiri/html_document.c +16 -0
- data/ext/nokogiri/html_sax_parser_context.c +59 -37
- data/ext/nokogiri/html_sax_push_parser.c +87 -0
- data/ext/nokogiri/html_sax_push_parser.h +9 -0
- data/ext/nokogiri/nokogiri.c +6 -8
- data/ext/nokogiri/nokogiri.h +3 -0
- data/ext/nokogiri/xml_document.c +101 -3
- data/ext/nokogiri/xml_document.h +3 -3
- data/ext/nokogiri/xml_node.c +150 -58
- data/ext/nokogiri/xml_node_set.c +169 -120
- data/ext/nokogiri/xml_node_set.h +5 -0
- data/ext/nokogiri/xml_sax_parser_context.c +64 -41
- data/ext/nokogiri/xml_text.c +2 -0
- data/ext/nokogiri/xml_xpath_context.c +30 -24
- data/ext/nokogiri/xslt_stylesheet.c +62 -16
- data/ext/nokogiri/xslt_stylesheet.h +5 -0
- data/lib/nokogiri/1.8/nokogiri.so +0 -0
- data/lib/nokogiri/1.9/nokogiri.so +0 -0
- data/lib/nokogiri/css/parser.rb +165 -159
- data/lib/nokogiri/css/parser.y +6 -3
- data/lib/nokogiri/css/tokenizer.rb +1 -1
- data/lib/nokogiri/css/tokenizer.rex +1 -1
- data/lib/nokogiri/html.rb +1 -0
- data/lib/nokogiri/html/document.rb +82 -42
- data/lib/nokogiri/html/sax/push_parser.rb +16 -0
- data/lib/nokogiri/version.rb +1 -1
- data/lib/nokogiri/xml.rb +6 -0
- data/lib/nokogiri/xml/builder.rb +7 -1
- data/lib/nokogiri/xml/document.rb +32 -17
- data/lib/nokogiri/xml/document_fragment.rb +6 -1
- data/lib/nokogiri/xml/node.rb +40 -9
- data/lib/nokogiri/xslt.rb +5 -1
- data/tasks/cross_compile.rb +1 -0
- data/tasks/nokogiri.org.rb +6 -0
- data/tasks/test.rb +1 -0
- data/test/css/test_xpath_visitor.rb +6 -0
- data/test/helper.rb +1 -0
- data/test/html/test_document.rb +26 -0
- data/test/html/test_document_fragment.rb +1 -2
- data/test/test_memory_leak.rb +81 -1
- data/test/test_xslt_transforms.rb +152 -123
- data/test/xml/test_builder.rb +24 -2
- data/test/xml/test_c14n.rb +151 -0
- data/test/xml/test_document.rb +48 -0
- data/test/xml/test_namespace.rb +5 -0
- data/test/xml/test_node.rb +82 -1
- data/test/xml/test_node_attributes.rb +19 -0
- data/test/xml/test_node_inheritance.rb +32 -0
- data/test/xml/test_node_reparenting.rb +32 -0
- data/test/xml/test_node_set.rb +16 -8
- data/test/xml/test_reader_encoding.rb +16 -0
- data/test/xml/test_unparented_node.rb +24 -0
- data/test/xml/test_xinclude.rb +83 -0
- data/test/xml/test_xpath.rb +22 -0
- metadata +159 -126
data/ext/nokogiri/xml_node_set.c
CHANGED
@@ -3,6 +3,69 @@
|
|
3
3
|
|
4
4
|
static ID decorate ;
|
5
5
|
|
6
|
+
static int dealloc_namespace(xmlNsPtr ns)
|
7
|
+
{
|
8
|
+
if (ns->href)
|
9
|
+
xmlFree((xmlChar *)ns->href);
|
10
|
+
if (ns->prefix)
|
11
|
+
xmlFree((xmlChar *)ns->prefix);
|
12
|
+
xmlFree(ns);
|
13
|
+
return ST_CONTINUE;
|
14
|
+
}
|
15
|
+
|
16
|
+
static void deallocate(nokogiriNodeSetTuple *tuple)
|
17
|
+
{
|
18
|
+
/*
|
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
|
+
*
|
29
|
+
* as a result, xmlXPathFreeNodeSet() will perform unsafe memory operations,
|
30
|
+
* and calling it would be evil.
|
31
|
+
*
|
32
|
+
* so here, we *manually* free the set of namespace nodes that was
|
33
|
+
* constructed at initialization time (see Nokogiri_wrap_xml_node_set()), as
|
34
|
+
* well as the NodeSet, without using the official xmlXPathFreeNodeSet().
|
35
|
+
*
|
36
|
+
* there's probably a lesson in here somewhere about intermingling, within a
|
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!
|
41
|
+
*
|
42
|
+
* "In Valgrind We Trust." seriously.
|
43
|
+
*/
|
44
|
+
xmlNodeSetPtr node_set;
|
45
|
+
|
46
|
+
node_set = tuple->node_set;
|
47
|
+
|
48
|
+
if (!node_set)
|
49
|
+
return;
|
50
|
+
|
51
|
+
NOKOGIRI_DEBUG_START(node_set) ;
|
52
|
+
st_foreach(tuple->namespaces, dealloc_namespace, 0);
|
53
|
+
|
54
|
+
if (node_set->nodeTab != NULL)
|
55
|
+
xmlFree(node_set->nodeTab);
|
56
|
+
|
57
|
+
xmlFree(node_set);
|
58
|
+
st_free_table(tuple->namespaces);
|
59
|
+
free(tuple);
|
60
|
+
NOKOGIRI_DEBUG_END(node_set) ;
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE allocate(VALUE klass)
|
64
|
+
{
|
65
|
+
return Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL), Qnil);
|
66
|
+
}
|
67
|
+
|
68
|
+
|
6
69
|
/*
|
7
70
|
* call-seq:
|
8
71
|
* dup
|
@@ -11,12 +74,12 @@ static ID decorate ;
|
|
11
74
|
*/
|
12
75
|
static VALUE duplicate(VALUE self)
|
13
76
|
{
|
14
|
-
|
77
|
+
nokogiriNodeSetTuple *tuple;
|
15
78
|
xmlNodeSetPtr dupl;
|
16
79
|
|
17
|
-
Data_Get_Struct(self,
|
80
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
18
81
|
|
19
|
-
dupl = xmlXPathNodeSetMerge(NULL, node_set);
|
82
|
+
dupl = xmlXPathNodeSetMerge(NULL, tuple->node_set);
|
20
83
|
|
21
84
|
return Nokogiri_wrap_xml_node_set(dupl, rb_iv_get(self, "@document"));
|
22
85
|
}
|
@@ -29,13 +92,10 @@ static VALUE duplicate(VALUE self)
|
|
29
92
|
*/
|
30
93
|
static VALUE length(VALUE self)
|
31
94
|
{
|
32
|
-
|
33
|
-
Data_Get_Struct(self,
|
95
|
+
nokogiriNodeSetTuple *tuple;
|
96
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
34
97
|
|
35
|
-
|
36
|
-
return INT2NUM(node_set->nodeNr);
|
37
|
-
|
38
|
-
return INT2NUM(0);
|
98
|
+
return tuple->node_set ? INT2NUM(tuple->node_set->nodeNr) : INT2NUM(0);
|
39
99
|
}
|
40
100
|
|
41
101
|
/*
|
@@ -46,15 +106,15 @@ static VALUE length(VALUE self)
|
|
46
106
|
*/
|
47
107
|
static VALUE push(VALUE self, VALUE rb_node)
|
48
108
|
{
|
49
|
-
|
109
|
+
nokogiriNodeSetTuple *tuple;
|
50
110
|
xmlNodePtr node;
|
51
111
|
|
52
112
|
if(!(rb_obj_is_kind_of(rb_node, cNokogiriXmlNode) || rb_obj_is_kind_of(rb_node, cNokogiriXmlNamespace)))
|
53
113
|
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
54
114
|
|
55
|
-
Data_Get_Struct(self,
|
115
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
56
116
|
Data_Get_Struct(rb_node, xmlNode, node);
|
57
|
-
xmlXPathNodeSetAdd(node_set, node);
|
117
|
+
xmlXPathNodeSetAdd(tuple->node_set, node);
|
58
118
|
return self;
|
59
119
|
}
|
60
120
|
|
@@ -65,23 +125,32 @@ static VALUE push(VALUE self, VALUE rb_node)
|
|
65
125
|
* Delete +node+ from the Nodeset, if it is a member. Returns the deleted node
|
66
126
|
* if found, otherwise returns nil.
|
67
127
|
*/
|
68
|
-
static VALUE
|
128
|
+
static VALUE
|
129
|
+
delete(VALUE self, VALUE rb_node)
|
69
130
|
{
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
131
|
+
nokogiriNodeSetTuple *tuple;
|
132
|
+
xmlNodePtr node;
|
133
|
+
xmlNodeSetPtr cur;
|
134
|
+
int i;
|
135
|
+
|
136
|
+
if (!(rb_obj_is_kind_of(rb_node, cNokogiriXmlNode) || rb_obj_is_kind_of(rb_node, cNokogiriXmlNamespace)))
|
137
|
+
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
138
|
+
|
139
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
140
|
+
Data_Get_Struct(rb_node, xmlNode, node);
|
141
|
+
cur = tuple->node_set;
|
142
|
+
|
143
|
+
if (xmlXPathNodeSetContains(cur, node)) {
|
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 ;
|
85
154
|
}
|
86
155
|
|
87
156
|
|
@@ -93,16 +162,17 @@ static VALUE delete(VALUE self, VALUE rb_node)
|
|
93
162
|
*/
|
94
163
|
static VALUE intersection(VALUE self, VALUE rb_other)
|
95
164
|
{
|
96
|
-
|
97
|
-
xmlNodeSetPtr
|
165
|
+
nokogiriNodeSetTuple *tuple, *other;
|
166
|
+
xmlNodeSetPtr intersection;
|
98
167
|
|
99
168
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
100
169
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
101
170
|
|
102
|
-
Data_Get_Struct(self,
|
103
|
-
Data_Get_Struct(rb_other,
|
171
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
172
|
+
Data_Get_Struct(rb_other, nokogiriNodeSetTuple, other);
|
104
173
|
|
105
|
-
|
174
|
+
intersection = xmlXPathIntersection(tuple->node_set, other->node_set);
|
175
|
+
return Nokogiri_wrap_xml_node_set(intersection, rb_iv_get(self, "@document"));
|
106
176
|
}
|
107
177
|
|
108
178
|
|
@@ -114,16 +184,16 @@ static VALUE intersection(VALUE self, VALUE rb_other)
|
|
114
184
|
*/
|
115
185
|
static VALUE include_eh(VALUE self, VALUE rb_node)
|
116
186
|
{
|
117
|
-
|
187
|
+
nokogiriNodeSetTuple *tuple;
|
118
188
|
xmlNodePtr node;
|
119
189
|
|
120
190
|
if(!(rb_obj_is_kind_of(rb_node, cNokogiriXmlNode) || rb_obj_is_kind_of(rb_node, cNokogiriXmlNamespace)))
|
121
191
|
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace");
|
122
192
|
|
123
|
-
Data_Get_Struct(self,
|
193
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
124
194
|
Data_Get_Struct(rb_node, xmlNode, node);
|
125
195
|
|
126
|
-
return (xmlXPathNodeSetContains(node_set, node) ? Qtrue : Qfalse);
|
196
|
+
return (xmlXPathNodeSetContains(tuple->node_set, node) ? Qtrue : Qfalse);
|
127
197
|
}
|
128
198
|
|
129
199
|
|
@@ -136,18 +206,17 @@ static VALUE include_eh(VALUE self, VALUE rb_node)
|
|
136
206
|
*/
|
137
207
|
static VALUE set_union(VALUE self, VALUE rb_other)
|
138
208
|
{
|
139
|
-
|
140
|
-
xmlNodeSetPtr other;
|
209
|
+
nokogiriNodeSetTuple *tuple, *other;
|
141
210
|
xmlNodeSetPtr new;
|
142
211
|
|
143
212
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
144
213
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
145
214
|
|
146
|
-
Data_Get_Struct(self,
|
147
|
-
Data_Get_Struct(rb_other,
|
215
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
216
|
+
Data_Get_Struct(rb_other, nokogiriNodeSetTuple, other);
|
148
217
|
|
149
|
-
new = xmlXPathNodeSetMerge(NULL, node_set);
|
150
|
-
new = xmlXPathNodeSetMerge(new, other);
|
218
|
+
new = xmlXPathNodeSetMerge(NULL, tuple->node_set);
|
219
|
+
new = xmlXPathNodeSetMerge(new, other->node_set);
|
151
220
|
|
152
221
|
return Nokogiri_wrap_xml_node_set(new, rb_iv_get(self, "@document"));
|
153
222
|
}
|
@@ -161,20 +230,19 @@ static VALUE set_union(VALUE self, VALUE rb_other)
|
|
161
230
|
*/
|
162
231
|
static VALUE minus(VALUE self, VALUE rb_other)
|
163
232
|
{
|
164
|
-
|
165
|
-
xmlNodeSetPtr other;
|
233
|
+
nokogiriNodeSetTuple *tuple, *other;
|
166
234
|
xmlNodeSetPtr new;
|
167
235
|
int j ;
|
168
236
|
|
169
237
|
if(!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet))
|
170
238
|
rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet");
|
171
239
|
|
172
|
-
Data_Get_Struct(self,
|
173
|
-
Data_Get_Struct(rb_other,
|
240
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
241
|
+
Data_Get_Struct(rb_other, nokogiriNodeSetTuple, other);
|
174
242
|
|
175
|
-
new = xmlXPathNodeSetMerge(NULL, node_set);
|
176
|
-
for (j = 0 ; j < other->nodeNr ; ++j) {
|
177
|
-
xmlXPathNodeSetDel(new, other->nodeTab[j]);
|
243
|
+
new = xmlXPathNodeSetMerge(NULL, tuple->node_set);
|
244
|
+
for (j = 0 ; j < other->node_set->nodeNr ; ++j) {
|
245
|
+
xmlXPathNodeSetDel(new, other->node_set->nodeTab[j]);
|
178
246
|
}
|
179
247
|
|
180
248
|
return Nokogiri_wrap_xml_node_set(new, rb_iv_get(self, "@document"));
|
@@ -184,10 +252,16 @@ static VALUE minus(VALUE self, VALUE rb_other)
|
|
184
252
|
static VALUE index_at(VALUE self, long offset)
|
185
253
|
{
|
186
254
|
xmlNodeSetPtr node_set;
|
187
|
-
|
255
|
+
nokogiriNodeSetTuple *tuple;
|
256
|
+
|
257
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
258
|
+
node_set = tuple->node_set;
|
259
|
+
|
260
|
+
if (offset >= node_set->nodeNr || abs((int)offset) > node_set->nodeNr)
|
261
|
+
return Qnil;
|
188
262
|
|
189
|
-
if
|
190
|
-
|
263
|
+
if (offset < 0)
|
264
|
+
offset += node_set->nodeNr;
|
191
265
|
|
192
266
|
if (XML_NAMESPACE_DECL == node_set->nodeTab[offset]->type)
|
193
267
|
return Nokogiri_wrap_xml_namespace2(rb_iv_get(self, "@document"), (xmlNsPtr)(node_set->nodeTab[offset]));
|
@@ -197,10 +271,12 @@ static VALUE index_at(VALUE self, long offset)
|
|
197
271
|
static VALUE subseq(VALUE self, long beg, long len)
|
198
272
|
{
|
199
273
|
long j;
|
274
|
+
nokogiriNodeSetTuple *tuple;
|
200
275
|
xmlNodeSetPtr node_set;
|
201
276
|
xmlNodeSetPtr new_set ;
|
202
277
|
|
203
|
-
Data_Get_Struct(self,
|
278
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
279
|
+
node_set = tuple->node_set;
|
204
280
|
|
205
281
|
if (beg > node_set->nodeNr) return Qnil ;
|
206
282
|
if (beg < 0 || len < 0) return Qnil ;
|
@@ -236,7 +312,9 @@ static VALUE slice(int argc, VALUE *argv, VALUE self)
|
|
236
312
|
VALUE arg ;
|
237
313
|
long beg, len ;
|
238
314
|
xmlNodeSetPtr node_set;
|
239
|
-
|
315
|
+
nokogiriNodeSetTuple *tuple;
|
316
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
317
|
+
node_set = tuple->node_set;
|
240
318
|
|
241
319
|
if (argc == 2) {
|
242
320
|
beg = NUM2LONG(argv[0]);
|
@@ -282,25 +360,17 @@ static VALUE to_array(VALUE self, VALUE rb_node)
|
|
282
360
|
VALUE *elts;
|
283
361
|
VALUE list;
|
284
362
|
int i;
|
363
|
+
nokogiriNodeSetTuple *tuple;
|
285
364
|
|
286
|
-
Data_Get_Struct(self,
|
365
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
366
|
+
set = tuple->node_set;
|
287
367
|
|
288
368
|
elts = calloc((size_t)set->nodeNr, sizeof(VALUE *));
|
289
369
|
for(i = 0; i < set->nodeNr; i++) {
|
290
|
-
if (XML_NAMESPACE_DECL == set->nodeTab[i]->type)
|
370
|
+
if (XML_NAMESPACE_DECL == set->nodeTab[i]->type)
|
291
371
|
elts[i] = Nokogiri_wrap_xml_namespace2(rb_iv_get(self, "@document"), (xmlNsPtr)(set->nodeTab[i]));
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
if(node->_private) {
|
296
|
-
if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE)
|
297
|
-
elts[i] = DOC_RUBY_OBJECT(node->doc);
|
298
|
-
else
|
299
|
-
elts[i] = (VALUE)node->_private;
|
300
|
-
} else {
|
301
|
-
elts[i] = Nokogiri_wrap_xml_node(Qnil, node);
|
302
|
-
}
|
303
|
-
}
|
372
|
+
else
|
373
|
+
elts[i] = Nokogiri_wrap_xml_node(Qnil, set->nodeTab[i]);
|
304
374
|
}
|
305
375
|
|
306
376
|
list = rb_ary_new4((long)set->nodeNr, elts);
|
@@ -320,8 +390,10 @@ static VALUE unlink_nodeset(VALUE self)
|
|
320
390
|
{
|
321
391
|
xmlNodeSetPtr node_set;
|
322
392
|
int j, nodeNr ;
|
393
|
+
nokogiriNodeSetTuple *tuple;
|
323
394
|
|
324
|
-
Data_Get_Struct(self,
|
395
|
+
Data_Get_Struct(self, nokogiriNodeSetTuple, tuple);
|
396
|
+
node_set = tuple->node_set;
|
325
397
|
nodeNr = node_set->nodeNr ;
|
326
398
|
for (j = 0 ; j < nodeNr ; j++) {
|
327
399
|
if (XML_NAMESPACE_DECL != node_set->nodeTab[j]->type) {
|
@@ -336,68 +408,45 @@ static VALUE unlink_nodeset(VALUE self)
|
|
336
408
|
return self ;
|
337
409
|
}
|
338
410
|
|
339
|
-
|
340
|
-
static void deallocate(xmlNodeSetPtr node_set)
|
341
|
-
{
|
342
|
-
/*
|
343
|
-
* xmlXPathFreeNodeSet() contains an implicit assumption that it is being
|
344
|
-
* called before any of its pointed-to nodes have been free()d. this
|
345
|
-
* assumption lies in the operation where it dereferences nodeTab pointers
|
346
|
-
* while searching for namespace nodes to free.
|
347
|
-
*
|
348
|
-
* however, since Ruby's GC mechanism cannot guarantee the strict order in
|
349
|
-
* which ruby objects will be GC'd, nodes may be garbage collected before a
|
350
|
-
* nodeset containing pointers to those nodes. (this is true regardless of
|
351
|
-
* how we declare dependencies between objects with rb_gc_mark().)
|
352
|
-
*
|
353
|
-
* as a result, xmlXPathFreeNodeSet() will perform unsafe memory operations,
|
354
|
-
* and calling it would be evil.
|
355
|
-
*
|
356
|
-
* on the bright side, though, Nokogiri's API currently does not cause
|
357
|
-
* namespace nodes to be included in node sets, ever.
|
358
|
-
*
|
359
|
-
* armed with that fact, we examined xmlXPathFreeNodeSet() and related libxml
|
360
|
-
* code and determined that, within the Nokogiri abstraction, we will not
|
361
|
-
* leak memory if we simply free the node set's memory directly. that's only
|
362
|
-
* quasi-evil!
|
363
|
-
*
|
364
|
-
* there's probably a lesson in here somewhere about intermingling, within a
|
365
|
-
* single array, structs with different memory-ownership semantics. or more
|
366
|
-
* generally, a lesson about building an API in C/C++ that does not contain
|
367
|
-
* assumptions about the strict order in which memory will be released. hey,
|
368
|
-
* that sounds like a great idea for a blog post! get to it!
|
369
|
-
*
|
370
|
-
* "In Valgrind We Trust." seriously.
|
371
|
-
*/
|
372
|
-
NOKOGIRI_DEBUG_START(node_set) ;
|
373
|
-
if (node_set->nodeTab != NULL)
|
374
|
-
xmlFree(node_set->nodeTab);
|
375
|
-
xmlFree(node_set);
|
376
|
-
NOKOGIRI_DEBUG_END(node_set) ;
|
377
|
-
}
|
378
|
-
|
379
|
-
static VALUE allocate(VALUE klass)
|
380
|
-
{
|
381
|
-
return Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL), Qnil);
|
382
|
-
}
|
383
|
-
|
384
411
|
VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set, VALUE document)
|
385
412
|
{
|
386
413
|
VALUE new_set ;
|
387
|
-
|
388
|
-
|
414
|
+
int i;
|
415
|
+
xmlNodePtr cur;
|
416
|
+
xmlNsPtr ns;
|
417
|
+
nokogiriNodeSetTuple *tuple;
|
418
|
+
|
419
|
+
new_set = Data_Make_Struct(cNokogiriXmlNodeSet, nokogiriNodeSetTuple, 0,
|
420
|
+
deallocate, tuple);
|
421
|
+
|
422
|
+
tuple->node_set = node_set;
|
423
|
+
tuple->namespaces = st_init_numtable();
|
424
|
+
|
425
|
+
if (!NIL_P(document)) {
|
389
426
|
rb_iv_set(new_set, "@document", document);
|
390
427
|
rb_funcall(document, decorate, 1, new_set);
|
391
428
|
}
|
429
|
+
|
430
|
+
if (node_set->nodeTab) {
|
431
|
+
for (i = 0; i < node_set->nodeNr; i++) {
|
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
|
+
}
|
440
|
+
|
392
441
|
return new_set ;
|
393
442
|
}
|
394
443
|
|
395
444
|
VALUE cNokogiriXmlNodeSet ;
|
396
445
|
void init_xml_node_set(void)
|
397
446
|
{
|
398
|
-
VALUE nokogiri
|
399
|
-
VALUE xml
|
400
|
-
VALUE klass
|
447
|
+
VALUE nokogiri = rb_define_module("Nokogiri");
|
448
|
+
VALUE xml = rb_define_module_under(nokogiri, "XML");
|
449
|
+
VALUE klass = rb_define_class_under(xml, "NodeSet", rb_cObject);
|
401
450
|
cNokogiriXmlNodeSet = klass;
|
402
451
|
|
403
452
|
rb_define_alloc_func(klass, allocate);
|
@@ -414,5 +463,5 @@ void init_xml_node_set(void)
|
|
414
463
|
rb_define_method(klass, "&", intersection, 1);
|
415
464
|
rb_define_method(klass, "include?", include_eh, 1);
|
416
465
|
|
417
|
-
decorate
|
466
|
+
decorate = rb_intern("decorate");
|
418
467
|
}
|
data/ext/nokogiri/xml_node_set.h
CHANGED
@@ -6,4 +6,9 @@ void init_xml_node_set();
|
|
6
6
|
|
7
7
|
extern VALUE cNokogiriXmlNodeSet ;
|
8
8
|
VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set, VALUE document) ;
|
9
|
+
|
10
|
+
typedef struct _nokogiriNodeSetTuple {
|
11
|
+
xmlNodeSetPtr node_set;
|
12
|
+
st_table *namespaces;
|
13
|
+
} nokogiriNodeSetTuple;
|
9
14
|
#endif
|