nokogiri 1.6.7.2-java → 1.6.8-java
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/.cross_rubies +2 -0
- data/.travis.yml +19 -9
- data/CHANGELOG.rdoc +73 -5
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +10 -9
- data/LICENSE.txt +1 -1
- data/Manifest.txt +7 -2
- data/README.md +23 -27
- data/ROADMAP.md +11 -1
- data/Rakefile +36 -17
- data/bin/nokogiri +2 -2
- data/dependencies.yml +29 -4
- data/ext/java/nokogiri/HtmlElementDescription.java +5 -2
- data/ext/java/nokogiri/NokogiriService.java +19 -0
- data/ext/java/nokogiri/XmlAttr.java +3 -1
- data/ext/java/nokogiri/XmlDocumentFragment.java +0 -14
- data/ext/java/nokogiri/XmlNode.java +106 -63
- data/ext/java/nokogiri/XmlXpathContext.java +12 -12
- data/ext/java/nokogiri/XsltStylesheet.java +11 -4
- data/ext/java/nokogiri/internals/HtmlDomParserContext.java +8 -1
- data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +1 -2
- data/ext/java/nokogiri/internals/NokogiriHelpers.java +7 -7
- data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +1 -1
- data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +0 -1
- data/ext/java/nokogiri/internals/NokogiriXsltErrorListener.java +3 -3
- data/ext/java/nokogiri/internals/ParserContext.java +4 -0
- data/ext/java/nokogiri/internals/SaveContextVisitor.java +18 -13
- data/ext/nokogiri/extconf.rb +163 -79
- data/ext/nokogiri/html_document.c +6 -6
- data/ext/nokogiri/html_element_description.c +1 -1
- data/ext/nokogiri/html_entity_lookup.c +1 -1
- data/ext/nokogiri/html_sax_parser_context.c +4 -4
- data/ext/nokogiri/html_sax_push_parser.c +2 -2
- data/ext/nokogiri/nokogiri.c +0 -7
- data/ext/nokogiri/nokogiri.h +1 -34
- data/ext/nokogiri/xml_attr.c +2 -2
- data/ext/nokogiri/xml_comment.c +1 -1
- data/ext/nokogiri/xml_document.c +20 -22
- data/ext/nokogiri/xml_encoding_handler.c +3 -3
- data/ext/nokogiri/xml_entity_reference.c +1 -1
- data/ext/nokogiri/xml_namespace.c +56 -17
- data/ext/nokogiri/xml_node.c +73 -67
- data/ext/nokogiri/xml_node_set.c +164 -146
- data/ext/nokogiri/xml_node_set.h +3 -4
- data/ext/nokogiri/xml_processing_instruction.c +2 -2
- data/ext/nokogiri/xml_reader.c +5 -18
- data/ext/nokogiri/xml_sax_parser.c +9 -12
- data/ext/nokogiri/xml_sax_parser_context.c +1 -1
- data/ext/nokogiri/xml_sax_push_parser.c +1 -1
- data/ext/nokogiri/xml_schema.c +1 -1
- data/ext/nokogiri/xml_syntax_error.c +0 -4
- data/ext/nokogiri/xml_syntax_error.h +0 -1
- data/ext/nokogiri/xml_text.c +1 -1
- data/ext/nokogiri/xml_xpath_context.c +15 -24
- data/ext/nokogiri/xslt_stylesheet.c +6 -6
- data/lib/nekohtml.jar +0 -0
- data/lib/nokogiri.rb +14 -7
- data/lib/nokogiri/css/parser.rb +8 -2
- data/lib/nokogiri/css/parser.y +7 -2
- data/lib/nokogiri/html/document.rb +4 -2
- data/lib/nokogiri/nokogiri.jar +0 -0
- 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 +6 -10
- data/lib/nokogiri/xml/node_set.rb +3 -3
- data/lib/nokogiri/xml/parse_options.rb +22 -0
- data/lib/serializer.jar +0 -0
- data/lib/xalan.jar +0 -0
- data/lib/xercesImpl.jar +0 -0
- data/lib/xml-apis.jar +0 -0
- data/tasks/test.rb +5 -0
- 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/helper.rb +4 -0
- data/test/html/sax/test_parser.rb +2 -2
- data/test/html/test_document.rb +47 -11
- data/test/html/test_document_encoding.rb +55 -58
- data/test/html/test_document_fragment.rb +27 -23
- data/test/html/test_node.rb +16 -0
- data/test/html/test_node_encoding.rb +71 -13
- data/test/namespaces/test_namespaces_in_parsed_doc.rb +14 -0
- data/test/test_css_cache.rb +1 -1
- data/test/test_encoding_handler.rb +2 -0
- data/test/test_xslt_transforms.rb +38 -3
- data/test/xml/sax/test_parser.rb +54 -53
- data/test/xml/test_document.rb +7 -2
- data/test/xml/test_document_encoding.rb +19 -16
- data/test/xml/test_document_fragment.rb +12 -0
- data/test/xml/test_dtd_encoding.rb +0 -2
- data/test/xml/test_namespace.rb +2 -2
- data/test/xml/test_node.rb +15 -4
- data/test/xml/test_node_attributes.rb +6 -0
- data/test/xml/test_node_encoding.rb +49 -87
- data/test/xml/test_node_reparenting.rb +193 -18
- data/test/xml/test_node_set.rb +1 -1
- data/test/xml/test_reader.rb +589 -0
- data/test/xml/test_reader_encoding.rb +100 -102
- data/test/xml/test_unparented_node.rb +14 -1
- data/test/xslt/test_exception_handling.rb +1 -1
- data/test_all +47 -33
- metadata +38 -36
- data/CHANGELOG.ja.rdoc +0 -1057
- data/test/test_reader.rb +0 -558
data/ext/nokogiri/xml_node.c
CHANGED
@@ -35,13 +35,13 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
35
35
|
xmlNsPtr ns;
|
36
36
|
|
37
37
|
if (reparented->type != XML_ATTRIBUTE_NODE &&
|
38
|
-
reparented->type != XML_ELEMENT_NODE) return;
|
38
|
+
reparented->type != XML_ELEMENT_NODE) { return; }
|
39
39
|
|
40
40
|
if (reparented->ns == NULL || reparented->ns->prefix == NULL) {
|
41
41
|
name = xmlSplitQName2(reparented->name, &prefix);
|
42
42
|
|
43
43
|
if(reparented->type == XML_ATTRIBUTE_NODE) {
|
44
|
-
if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) return;
|
44
|
+
if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) { return; }
|
45
45
|
}
|
46
46
|
|
47
47
|
ns = xmlSearchNs(reparented->doc, reparented, prefix);
|
@@ -57,18 +57,19 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
57
57
|
}
|
58
58
|
|
59
59
|
/* Avoid segv when relinking against unlinked nodes. */
|
60
|
-
if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) return;
|
60
|
+
if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
|
61
61
|
|
62
62
|
/* Make sure that our reparented node has the correct namespaces */
|
63
|
-
if(!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent)
|
63
|
+
if (!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent) {
|
64
64
|
xmlSetNs(reparented, reparented->parent->ns);
|
65
|
+
}
|
65
66
|
|
66
67
|
/* Search our parents for an existing definition */
|
67
|
-
if(reparented->nsDef) {
|
68
|
+
if (reparented->nsDef) {
|
68
69
|
xmlNsPtr curr = reparented->nsDef;
|
69
70
|
xmlNsPtr prev = NULL;
|
70
71
|
|
71
|
-
while(curr) {
|
72
|
+
while (curr) {
|
72
73
|
xmlNsPtr ns = xmlSearchNsByHref(
|
73
74
|
reparented->doc,
|
74
75
|
reparented->parent,
|
@@ -76,7 +77,7 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
76
77
|
);
|
77
78
|
/* If we find the namespace is already declared, remove it from this
|
78
79
|
* definition list. */
|
79
|
-
if(ns && ns != curr) {
|
80
|
+
if (ns && ns != curr && xmlStrEqual(ns->prefix, curr->prefix)) {
|
80
81
|
if (prev) {
|
81
82
|
prev->next = curr->next;
|
82
83
|
} else {
|
@@ -92,12 +93,12 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
92
93
|
|
93
94
|
/* Only walk all children if there actually is a namespace we need to */
|
94
95
|
/* reparent. */
|
95
|
-
if(NULL == reparented->ns) return;
|
96
|
+
if (NULL == reparented->ns) { return; }
|
96
97
|
|
97
98
|
/* When a node gets reparented, walk it's children to make sure that */
|
98
99
|
/* their namespaces are reparented as well. */
|
99
100
|
child = reparented->children;
|
100
|
-
while(NULL != child) {
|
101
|
+
while (NULL != child) {
|
101
102
|
relink_namespace(child);
|
102
103
|
child = child->next;
|
103
104
|
}
|
@@ -140,6 +141,7 @@ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_rep
|
|
140
141
|
{
|
141
142
|
VALUE reparented_obj ;
|
142
143
|
xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text, parent ;
|
144
|
+
int original_ns_prefix_is_default = 0 ;
|
143
145
|
|
144
146
|
if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode))
|
145
147
|
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
@@ -233,18 +235,38 @@ ok:
|
|
233
235
|
* uninteresting libxml2 implementation detail). as a result, we cannot
|
234
236
|
* reparent the actual reparentee, so we reparent a duplicate.
|
235
237
|
*/
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
238
|
+
if (reparentee->type == XML_TEXT_NODE && reparentee->_private) {
|
239
|
+
/*
|
240
|
+
* additionally, since we know this C struct isn't going to be related to
|
241
|
+
* a Ruby object anymore, let's break the relationship on this end as
|
242
|
+
* well.
|
243
|
+
*
|
244
|
+
* this is not absolutely necessary unless libxml-ruby is also in effect,
|
245
|
+
* in which case its global callback `rxml_node_deregisterNode` will try
|
246
|
+
* to do things to our data.
|
247
|
+
*
|
248
|
+
* for more details on this particular (and particularly nasty) edge
|
249
|
+
* case, see:
|
250
|
+
*
|
251
|
+
* https://github.com/sparklemotion/nokogiri/issues/1426
|
252
|
+
*/
|
253
|
+
reparentee->_private = NULL ;
|
254
|
+
}
|
240
255
|
|
241
|
-
reparentee
|
256
|
+
if (reparentee->ns != NULL && reparentee->ns->prefix == NULL) {
|
257
|
+
original_ns_prefix_is_default = 1;
|
258
|
+
}
|
242
259
|
|
243
|
-
|
260
|
+
nokogiri_root_node(reparentee);
|
244
261
|
|
245
|
-
if (! reparentee) {
|
262
|
+
if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
|
246
263
|
rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
|
247
264
|
}
|
265
|
+
|
266
|
+
if (original_ns_prefix_is_default && reparentee->ns != NULL && reparentee->ns->prefix != NULL) {
|
267
|
+
/* issue #391, where new node's prefix may become the string "default" */
|
268
|
+
reparentee->ns->prefix = NULL;
|
269
|
+
}
|
248
270
|
}
|
249
271
|
|
250
272
|
if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling
|
@@ -339,7 +361,7 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
|
|
339
361
|
Data_Get_Struct(self, xmlNode, node);
|
340
362
|
encoded = xmlEncodeSpecialChars(
|
341
363
|
node->doc,
|
342
|
-
(const xmlChar *)
|
364
|
+
(const xmlChar *)StringValueCStr(string)
|
343
365
|
);
|
344
366
|
|
345
367
|
encoded_str = NOKOGIRI_STR_NEW2(encoded);
|
@@ -375,9 +397,9 @@ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, V
|
|
375
397
|
|
376
398
|
dtd = xmlCreateIntSubset(
|
377
399
|
doc,
|
378
|
-
NIL_P(name) ? NULL : (const xmlChar *)
|
379
|
-
NIL_P(external_id) ? NULL : (const xmlChar *)
|
380
|
-
NIL_P(system_id) ? NULL : (const xmlChar *)
|
400
|
+
NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name),
|
401
|
+
NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id),
|
402
|
+
NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
|
381
403
|
);
|
382
404
|
|
383
405
|
if(!dtd) return Qnil;
|
@@ -406,9 +428,9 @@ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, V
|
|
406
428
|
|
407
429
|
dtd = xmlNewDtd(
|
408
430
|
doc,
|
409
|
-
NIL_P(name) ? NULL : (const xmlChar *)
|
410
|
-
NIL_P(external_id) ? NULL : (const xmlChar *)
|
411
|
-
NIL_P(system_id) ? NULL : (const xmlChar *)
|
431
|
+
NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name),
|
432
|
+
NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id),
|
433
|
+
NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
|
412
434
|
);
|
413
435
|
|
414
436
|
if(!dtd) return Qnil;
|
@@ -481,13 +503,7 @@ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
|
|
481
503
|
|
482
504
|
Data_Get_Struct(self, xmlNode, node);
|
483
505
|
|
484
|
-
xmlResetLastError();
|
485
|
-
xmlSetStructuredErrorFunc(NULL, Nokogiri_error_silencer);
|
486
|
-
|
487
506
|
dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
|
488
|
-
|
489
|
-
xmlSetStructuredErrorFunc(NULL, NULL);
|
490
|
-
|
491
507
|
if(dup == NULL) return Qnil;
|
492
508
|
|
493
509
|
nokogiri_root_node(dup);
|
@@ -751,7 +767,7 @@ static VALUE key_eh(VALUE self, VALUE attribute)
|
|
751
767
|
{
|
752
768
|
xmlNodePtr node;
|
753
769
|
Data_Get_Struct(self, xmlNode, node);
|
754
|
-
if(xmlHasProp(node, (xmlChar *)
|
770
|
+
if(xmlHasProp(node, (xmlChar *)StringValueCStr(attribute)))
|
755
771
|
return Qtrue;
|
756
772
|
return Qfalse;
|
757
773
|
}
|
@@ -766,8 +782,8 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
|
766
782
|
{
|
767
783
|
xmlNodePtr node;
|
768
784
|
Data_Get_Struct(self, xmlNode, node);
|
769
|
-
if(xmlHasNsProp(node, (xmlChar *)
|
770
|
-
NIL_P(namespace) ? NULL : (xmlChar *)
|
785
|
+
if(xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
|
786
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace)))
|
771
787
|
return Qtrue;
|
772
788
|
return Qfalse;
|
773
789
|
}
|
@@ -778,19 +794,11 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
|
778
794
|
*
|
779
795
|
* Set the +property+ to +value+
|
780
796
|
*/
|
781
|
-
static VALUE set(VALUE
|
797
|
+
static VALUE set(VALUE self, VALUE property, VALUE value)
|
782
798
|
{
|
783
799
|
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);
|
800
|
+
xmlAttrPtr prop;
|
801
|
+
Data_Get_Struct(self, xmlNode, node);
|
794
802
|
|
795
803
|
/* If a matching attribute node already exists, then xmlSetProp will destroy
|
796
804
|
* the existing node's children. However, if Nokogiri has a node object
|
@@ -798,9 +806,11 @@ static VALUE set(VALUE node_rb, VALUE property_name_rb, VALUE property_value_rb)
|
|
798
806
|
*
|
799
807
|
* We can avoid this by unlinking these nodes first.
|
800
808
|
*/
|
801
|
-
|
802
|
-
|
803
|
-
|
809
|
+
if (node->type != XML_ELEMENT_NODE)
|
810
|
+
return(Qnil);
|
811
|
+
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property));
|
812
|
+
if (prop && prop->children) {
|
813
|
+
for (cur = prop->children; cur; cur = cur->next) {
|
804
814
|
if (cur->_private) {
|
805
815
|
nokogiri_root_node(cur);
|
806
816
|
xmlUnlinkNode(cur);
|
@@ -808,14 +818,10 @@ static VALUE set(VALUE node_rb, VALUE property_name_rb, VALUE property_value_rb)
|
|
808
818
|
}
|
809
819
|
}
|
810
820
|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
xmlSetProp(node, property_name, (xmlChar *)StringValuePtr(property_value_rb));
|
815
|
-
|
816
|
-
xmlSetStructuredErrorFunc(NULL, NULL);
|
821
|
+
xmlSetProp(node, (xmlChar *)StringValueCStr(property),
|
822
|
+
(xmlChar *)StringValueCStr(value));
|
817
823
|
|
818
|
-
return
|
824
|
+
return value;
|
819
825
|
}
|
820
826
|
|
821
827
|
/*
|
@@ -836,7 +842,7 @@ static VALUE get(VALUE self, VALUE rattribute)
|
|
836
842
|
if (NIL_P(rattribute)) return Qnil;
|
837
843
|
|
838
844
|
Data_Get_Struct(self, xmlNode, node);
|
839
|
-
attribute = strdup(
|
845
|
+
attribute = strdup(StringValueCStr(rattribute));
|
840
846
|
|
841
847
|
colon = strchr(attribute, ':');
|
842
848
|
if (colon) {
|
@@ -847,7 +853,7 @@ static VALUE get(VALUE self, VALUE rattribute)
|
|
847
853
|
if (ns) {
|
848
854
|
value = xmlGetNsProp(node, (xmlChar*)(attr_name), ns->href);
|
849
855
|
} else {
|
850
|
-
value = xmlGetProp(node, (xmlChar*)
|
856
|
+
value = xmlGetProp(node, (xmlChar*)StringValueCStr(rattribute));
|
851
857
|
}
|
852
858
|
} else {
|
853
859
|
value = xmlGetNoNsProp(node, (xmlChar*)attribute);
|
@@ -894,7 +900,7 @@ static VALUE attr(VALUE self, VALUE name)
|
|
894
900
|
xmlNodePtr node;
|
895
901
|
xmlAttrPtr prop;
|
896
902
|
Data_Get_Struct(self, xmlNode, node);
|
897
|
-
prop = xmlHasProp(node, (xmlChar *)
|
903
|
+
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
898
904
|
|
899
905
|
if(! prop) return Qnil;
|
900
906
|
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
@@ -911,8 +917,8 @@ static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
|
911
917
|
xmlNodePtr node;
|
912
918
|
xmlAttrPtr prop;
|
913
919
|
Data_Get_Struct(self, xmlNode, node);
|
914
|
-
prop = xmlHasNsProp(node, (xmlChar *)
|
915
|
-
NIL_P(namespace) ? NULL : (xmlChar *)
|
920
|
+
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
921
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
916
922
|
|
917
923
|
if(! prop) return Qnil;
|
918
924
|
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
@@ -1049,7 +1055,7 @@ static VALUE set_native_content(VALUE self, VALUE content)
|
|
1049
1055
|
child = next ;
|
1050
1056
|
}
|
1051
1057
|
|
1052
|
-
xmlNodeSetContent(node, (xmlChar *)
|
1058
|
+
xmlNodeSetContent(node, (xmlChar *)StringValueCStr(content));
|
1053
1059
|
return content;
|
1054
1060
|
}
|
1055
1061
|
|
@@ -1087,7 +1093,7 @@ static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
|
|
1087
1093
|
xmlChar* lang ;
|
1088
1094
|
|
1089
1095
|
Data_Get_Struct(self_rb, xmlNode, self);
|
1090
|
-
lang = (xmlChar*)
|
1096
|
+
lang = (xmlChar*)StringValueCStr(lang_rb);
|
1091
1097
|
|
1092
1098
|
xmlNodeSetLang(self, lang);
|
1093
1099
|
|
@@ -1152,7 +1158,7 @@ static VALUE set_name(VALUE self, VALUE new_name)
|
|
1152
1158
|
{
|
1153
1159
|
xmlNodePtr node;
|
1154
1160
|
Data_Get_Struct(self, xmlNode, node);
|
1155
|
-
xmlNodeSetName(node, (xmlChar*)
|
1161
|
+
xmlNodeSetName(node, (xmlChar*)StringValueCStr(new_name));
|
1156
1162
|
return new_name;
|
1157
1163
|
}
|
1158
1164
|
|
@@ -1226,13 +1232,13 @@ static VALUE native_write_to(
|
|
1226
1232
|
|
1227
1233
|
before_indent = xmlTreeIndentString;
|
1228
1234
|
|
1229
|
-
xmlTreeIndentString =
|
1235
|
+
xmlTreeIndentString = StringValueCStr(indent_string);
|
1230
1236
|
|
1231
1237
|
savectx = xmlSaveToIO(
|
1232
1238
|
(xmlOutputWriteCallback)io_write_callback,
|
1233
1239
|
(xmlOutputCloseCallback)io_close_callback,
|
1234
1240
|
(void *)io,
|
1235
|
-
RTEST(encoding) ?
|
1241
|
+
RTEST(encoding) ? StringValueCStr(encoding) : NULL,
|
1236
1242
|
(int)NUM2INT(options)
|
1237
1243
|
);
|
1238
1244
|
|
@@ -1279,7 +1285,7 @@ static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
|
|
1279
1285
|
ns = xmlSearchNs(
|
1280
1286
|
node->doc,
|
1281
1287
|
node,
|
1282
|
-
(const xmlChar *)(NIL_P(prefix) ? NULL :
|
1288
|
+
(const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
|
1283
1289
|
);
|
1284
1290
|
|
1285
1291
|
if(!ns) {
|
@@ -1288,8 +1294,8 @@ static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
|
|
1288
1294
|
}
|
1289
1295
|
ns = xmlNewNs(
|
1290
1296
|
namespacee,
|
1291
|
-
(const xmlChar *)
|
1292
|
-
(const xmlChar *)(NIL_P(prefix) ? NULL :
|
1297
|
+
(const xmlChar *)StringValueCStr(href),
|
1298
|
+
(const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
|
1293
1299
|
);
|
1294
1300
|
}
|
1295
1301
|
|
@@ -1319,7 +1325,7 @@ static VALUE new(int argc, VALUE *argv, VALUE klass)
|
|
1319
1325
|
|
1320
1326
|
Data_Get_Struct(document, xmlDoc, doc);
|
1321
1327
|
|
1322
|
-
node = xmlNewNode(NULL, (xmlChar *)
|
1328
|
+
node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(name));
|
1323
1329
|
node->doc = doc->doc;
|
1324
1330
|
nokogiri_root_node(node);
|
1325
1331
|
|
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,27 +320,18 @@ 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
|
360
|
-
VALUE *elts;
|
323
|
+
xmlNodeSetPtr node_set ;
|
361
324
|
VALUE list;
|
362
325
|
int i;
|
363
|
-
nokogiriNodeSetTuple *tuple;
|
364
326
|
|
365
|
-
Data_Get_Struct(self,
|
366
|
-
set = tuple->node_set;
|
327
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
367
328
|
|
368
|
-
|
369
|
-
for(i = 0; i <
|
370
|
-
|
371
|
-
|
372
|
-
else
|
373
|
-
elts[i] = Nokogiri_wrap_xml_node(Qnil, set->nodeTab[i]);
|
329
|
+
list = rb_ary_new2(node_set->nodeNr);
|
330
|
+
for(i = 0; i < node_set->nodeNr; i++) {
|
331
|
+
VALUE elt = Nokogiri_wrap_xml_node_set_node(node_set->nodeTab[i], self);
|
332
|
+
rb_ary_push( list, elt );
|
374
333
|
}
|
375
334
|
|
376
|
-
list = rb_ary_new4((long)set->nodeNr, elts);
|
377
|
-
|
378
|
-
/*free(elts); */
|
379
|
-
|
380
335
|
return list;
|
381
336
|
}
|
382
337
|
|
@@ -390,13 +345,12 @@ static VALUE unlink_nodeset(VALUE self)
|
|
390
345
|
{
|
391
346
|
xmlNodeSetPtr node_set;
|
392
347
|
int j, nodeNr ;
|
393
|
-
nokogiriNodeSetTuple *tuple;
|
394
348
|
|
395
|
-
Data_Get_Struct(self,
|
396
|
-
|
349
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
350
|
+
|
397
351
|
nodeNr = node_set->nodeNr ;
|
398
352
|
for (j = 0 ; j < nodeNr ; j++) {
|
399
|
-
if (
|
353
|
+
if (! Nokogiri_namespace_eh(node_set->nodeTab[j])) {
|
400
354
|
VALUE node ;
|
401
355
|
xmlNodePtr node_ptr;
|
402
356
|
node = Nokogiri_wrap_xml_node(Qnil, node_set->nodeTab[j]);
|
@@ -408,39 +362,103 @@ static VALUE unlink_nodeset(VALUE self)
|
|
408
362
|
return self ;
|
409
363
|
}
|
410
364
|
|
365
|
+
|
366
|
+
static void reify_node_set_namespaces(VALUE self)
|
367
|
+
{
|
368
|
+
/*
|
369
|
+
* as mentioned in deallocate() above, xmlNs structs returned in an XPath
|
370
|
+
* NodeSet are duplicates, and we don't clean them up at deallocate() time.
|
371
|
+
*
|
372
|
+
* as a result, we need to make sure the Ruby manages this memory. we do this
|
373
|
+
* by forcing the creation of a Ruby object wrapped around the xmlNs.
|
374
|
+
*
|
375
|
+
* we also have to make sure that the NodeSet has a reference to the
|
376
|
+
* Namespace object, otherwise GC will kick in and the Namespace won't be
|
377
|
+
* marked.
|
378
|
+
*
|
379
|
+
* we *could* do this safely with *all* the nodes in the NodeSet, but we only
|
380
|
+
* *need* to do it for xmlNs structs, and so you get the code we have here.
|
381
|
+
*/
|
382
|
+
int j ;
|
383
|
+
xmlNodeSetPtr node_set ;
|
384
|
+
VALUE namespace_cache ;
|
385
|
+
|
386
|
+
Data_Get_Struct(self, xmlNodeSet, node_set);
|
387
|
+
|
388
|
+
namespace_cache = rb_iv_get(self, "@namespace_cache");
|
389
|
+
|
390
|
+
for (j = 0 ; j < node_set->nodeNr ; j++) {
|
391
|
+
if (Nokogiri_namespace_eh(node_set->nodeTab[j])) {
|
392
|
+
rb_ary_push(namespace_cache, Nokogiri_wrap_xml_node_set_node(node_set->nodeTab[j], self));
|
393
|
+
}
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
|
411
398
|
VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set, VALUE document)
|
412
399
|
{
|
413
400
|
VALUE new_set ;
|
414
|
-
int i;
|
415
|
-
xmlNodePtr cur;
|
416
|
-
xmlNsPtr ns;
|
417
|
-
nokogiriNodeSetTuple *tuple;
|
418
401
|
|
419
|
-
|
420
|
-
|
402
|
+
if (node_set == NULL) {
|
403
|
+
node_set = xmlXPathNodeSetCreate(NULL);
|
404
|
+
}
|
421
405
|
|
422
|
-
|
423
|
-
tuple->namespaces = st_init_numtable();
|
406
|
+
new_set = Data_Wrap_Struct(cNokogiriXmlNodeSet, 0, deallocate, node_set);
|
424
407
|
|
425
408
|
if (!NIL_P(document)) {
|
426
409
|
rb_iv_set(new_set, "@document", document);
|
427
410
|
rb_funcall(document, decorate, 1, new_set);
|
428
411
|
}
|
429
412
|
|
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
|
-
}
|
413
|
+
rb_iv_set(new_set, "@namespace_cache", rb_ary_new());
|
414
|
+
reify_node_set_namespaces(new_set);
|
440
415
|
|
441
416
|
return new_set ;
|
442
417
|
}
|
443
418
|
|
419
|
+
VALUE Nokogiri_wrap_xml_node_set_node(xmlNodePtr node, VALUE node_set)
|
420
|
+
{
|
421
|
+
xmlDocPtr document ;
|
422
|
+
|
423
|
+
if (Nokogiri_namespace_eh(node)) {
|
424
|
+
Data_Get_Struct(rb_iv_get(node_set, "@document"), xmlDoc, document);
|
425
|
+
return Nokogiri_wrap_xml_namespace(document, (xmlNsPtr)node);
|
426
|
+
} else {
|
427
|
+
return Nokogiri_wrap_xml_node(Qnil, node);
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
|
432
|
+
static void xpath_node_set_del(xmlNodeSetPtr cur, xmlNodePtr val)
|
433
|
+
{
|
434
|
+
/*
|
435
|
+
* as mentioned a few times above, we do not want to free xmlNs structs
|
436
|
+
* outside of the Namespace lifecycle.
|
437
|
+
*
|
438
|
+
* xmlXPathNodeSetDel() frees xmlNs structs, and so here we reproduce that
|
439
|
+
* function with the xmlNs logic.
|
440
|
+
*/
|
441
|
+
int i;
|
442
|
+
|
443
|
+
if (cur == NULL) return;
|
444
|
+
if (val == NULL) return;
|
445
|
+
|
446
|
+
/*
|
447
|
+
* find node in nodeTab
|
448
|
+
*/
|
449
|
+
for (i = 0;i < cur->nodeNr;i++)
|
450
|
+
if (cur->nodeTab[i] == val) break;
|
451
|
+
|
452
|
+
if (i >= cur->nodeNr) { /* not found */
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
cur->nodeNr--;
|
456
|
+
for (;i < cur->nodeNr;i++)
|
457
|
+
cur->nodeTab[i] = cur->nodeTab[i + 1];
|
458
|
+
cur->nodeTab[cur->nodeNr] = NULL;
|
459
|
+
}
|
460
|
+
|
461
|
+
|
444
462
|
VALUE cNokogiriXmlNodeSet ;
|
445
463
|
void init_xml_node_set(void)
|
446
464
|
{
|