nokogiri 1.10.9 → 1.13.6

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.

Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/LICENSE-DEPENDENCIES.md +1173 -884
  4. data/LICENSE.md +1 -1
  5. data/README.md +178 -96
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +13 -64
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +746 -424
  10. data/ext/nokogiri/gumbo.c +584 -0
  11. data/ext/nokogiri/html4_document.c +166 -0
  12. data/ext/nokogiri/html4_element_description.c +294 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser_context.c +119 -0
  15. data/ext/nokogiri/html4_sax_push_parser.c +95 -0
  16. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  17. data/ext/nokogiri/nokogiri.c +228 -91
  18. data/ext/nokogiri/nokogiri.h +191 -89
  19. data/ext/nokogiri/test_global_handlers.c +40 -0
  20. data/ext/nokogiri/xml_attr.c +15 -15
  21. data/ext/nokogiri/xml_attribute_decl.c +18 -18
  22. data/ext/nokogiri/xml_cdata.c +13 -18
  23. data/ext/nokogiri/xml_comment.c +19 -26
  24. data/ext/nokogiri/xml_document.c +291 -219
  25. data/ext/nokogiri/xml_document_fragment.c +12 -16
  26. data/ext/nokogiri/xml_dtd.c +56 -50
  27. data/ext/nokogiri/xml_element_content.c +31 -26
  28. data/ext/nokogiri/xml_element_decl.c +22 -22
  29. data/ext/nokogiri/xml_encoding_handler.c +43 -18
  30. data/ext/nokogiri/xml_entity_decl.c +32 -30
  31. data/ext/nokogiri/xml_entity_reference.c +16 -18
  32. data/ext/nokogiri/xml_namespace.c +60 -51
  33. data/ext/nokogiri/xml_node.c +1001 -610
  34. data/ext/nokogiri/xml_node_set.c +174 -162
  35. data/ext/nokogiri/xml_processing_instruction.c +17 -19
  36. data/ext/nokogiri/xml_reader.c +226 -175
  37. data/ext/nokogiri/xml_relax_ng.c +52 -28
  38. data/ext/nokogiri/xml_sax_parser.c +112 -112
  39. data/ext/nokogiri/xml_sax_parser_context.c +112 -86
  40. data/ext/nokogiri/xml_sax_push_parser.c +36 -27
  41. data/ext/nokogiri/xml_schema.c +96 -46
  42. data/ext/nokogiri/xml_syntax_error.c +42 -21
  43. data/ext/nokogiri/xml_text.c +13 -17
  44. data/ext/nokogiri/xml_xpath_context.c +223 -115
  45. data/ext/nokogiri/xslt_stylesheet.c +265 -173
  46. data/gumbo-parser/CHANGES.md +63 -0
  47. data/gumbo-parser/Makefile +101 -0
  48. data/gumbo-parser/THANKS +27 -0
  49. data/gumbo-parser/src/Makefile +34 -0
  50. data/gumbo-parser/src/README.md +41 -0
  51. data/gumbo-parser/src/ascii.c +75 -0
  52. data/gumbo-parser/src/ascii.h +115 -0
  53. data/gumbo-parser/src/attribute.c +42 -0
  54. data/gumbo-parser/src/attribute.h +17 -0
  55. data/gumbo-parser/src/char_ref.c +22225 -0
  56. data/gumbo-parser/src/char_ref.h +29 -0
  57. data/gumbo-parser/src/char_ref.rl +2154 -0
  58. data/gumbo-parser/src/error.c +626 -0
  59. data/gumbo-parser/src/error.h +148 -0
  60. data/gumbo-parser/src/foreign_attrs.c +104 -0
  61. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  62. data/gumbo-parser/src/gumbo.h +943 -0
  63. data/gumbo-parser/src/insertion_mode.h +33 -0
  64. data/gumbo-parser/src/macros.h +91 -0
  65. data/gumbo-parser/src/parser.c +4875 -0
  66. data/gumbo-parser/src/parser.h +41 -0
  67. data/gumbo-parser/src/replacement.h +33 -0
  68. data/gumbo-parser/src/string_buffer.c +103 -0
  69. data/gumbo-parser/src/string_buffer.h +68 -0
  70. data/gumbo-parser/src/string_piece.c +48 -0
  71. data/gumbo-parser/src/svg_attrs.c +174 -0
  72. data/gumbo-parser/src/svg_attrs.gperf +77 -0
  73. data/gumbo-parser/src/svg_tags.c +137 -0
  74. data/gumbo-parser/src/svg_tags.gperf +55 -0
  75. data/gumbo-parser/src/tag.c +222 -0
  76. data/gumbo-parser/src/tag_lookup.c +382 -0
  77. data/gumbo-parser/src/tag_lookup.gperf +169 -0
  78. data/gumbo-parser/src/tag_lookup.h +13 -0
  79. data/gumbo-parser/src/token_buffer.c +79 -0
  80. data/gumbo-parser/src/token_buffer.h +71 -0
  81. data/gumbo-parser/src/token_type.h +17 -0
  82. data/gumbo-parser/src/tokenizer.c +3463 -0
  83. data/gumbo-parser/src/tokenizer.h +112 -0
  84. data/gumbo-parser/src/tokenizer_states.h +339 -0
  85. data/gumbo-parser/src/utf8.c +245 -0
  86. data/gumbo-parser/src/utf8.h +164 -0
  87. data/gumbo-parser/src/util.c +68 -0
  88. data/gumbo-parser/src/util.h +30 -0
  89. data/gumbo-parser/src/vector.c +111 -0
  90. data/gumbo-parser/src/vector.h +45 -0
  91. data/lib/nokogiri/class_resolver.rb +67 -0
  92. data/lib/nokogiri/css/node.rb +10 -8
  93. data/lib/nokogiri/css/parser.rb +397 -377
  94. data/lib/nokogiri/css/parser.y +250 -245
  95. data/lib/nokogiri/css/parser_extras.rb +54 -49
  96. data/lib/nokogiri/css/syntax_error.rb +3 -1
  97. data/lib/nokogiri/css/tokenizer.rb +5 -3
  98. data/lib/nokogiri/css/tokenizer.rex +3 -2
  99. data/lib/nokogiri/css/xpath_visitor.rb +218 -91
  100. data/lib/nokogiri/css.rb +50 -17
  101. data/lib/nokogiri/decorators/slop.rb +9 -7
  102. data/lib/nokogiri/extension.rb +31 -0
  103. data/lib/nokogiri/gumbo.rb +15 -0
  104. data/lib/nokogiri/html.rb +38 -27
  105. data/lib/nokogiri/{html → html4}/builder.rb +4 -2
  106. data/lib/nokogiri/{html → html4}/document.rb +103 -105
  107. data/lib/nokogiri/html4/document_fragment.rb +54 -0
  108. data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
  109. data/lib/nokogiri/html4/element_description_defaults.rb +578 -0
  110. data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
  111. data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
  112. data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
  113. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
  114. data/lib/nokogiri/html4.rb +46 -0
  115. data/lib/nokogiri/html5/document.rb +91 -0
  116. data/lib/nokogiri/html5/document_fragment.rb +83 -0
  117. data/lib/nokogiri/html5/node.rb +100 -0
  118. data/lib/nokogiri/html5.rb +478 -0
  119. data/lib/nokogiri/jruby/dependencies.rb +21 -0
  120. data/lib/nokogiri/syntax_error.rb +2 -0
  121. data/lib/nokogiri/version/constant.rb +6 -0
  122. data/lib/nokogiri/version/info.rb +222 -0
  123. data/lib/nokogiri/version.rb +3 -108
  124. data/lib/nokogiri/xml/attr.rb +6 -3
  125. data/lib/nokogiri/xml/attribute_decl.rb +3 -1
  126. data/lib/nokogiri/xml/builder.rb +74 -33
  127. data/lib/nokogiri/xml/cdata.rb +3 -1
  128. data/lib/nokogiri/xml/character_data.rb +2 -0
  129. data/lib/nokogiri/xml/document.rb +224 -86
  130. data/lib/nokogiri/xml/document_fragment.rb +46 -44
  131. data/lib/nokogiri/xml/dtd.rb +4 -2
  132. data/lib/nokogiri/xml/element_content.rb +2 -0
  133. data/lib/nokogiri/xml/element_decl.rb +3 -1
  134. data/lib/nokogiri/xml/entity_decl.rb +4 -2
  135. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  136. data/lib/nokogiri/xml/namespace.rb +3 -0
  137. data/lib/nokogiri/xml/node/save_options.rb +10 -5
  138. data/lib/nokogiri/xml/node.rb +884 -378
  139. data/lib/nokogiri/xml/node_set.rb +51 -54
  140. data/lib/nokogiri/xml/notation.rb +13 -0
  141. data/lib/nokogiri/xml/parse_options.rb +22 -8
  142. data/lib/nokogiri/xml/pp/character_data.rb +9 -6
  143. data/lib/nokogiri/xml/pp/node.rb +25 -26
  144. data/lib/nokogiri/xml/pp.rb +4 -2
  145. data/lib/nokogiri/xml/processing_instruction.rb +3 -1
  146. data/lib/nokogiri/xml/reader.rb +23 -28
  147. data/lib/nokogiri/xml/relax_ng.rb +8 -2
  148. data/lib/nokogiri/xml/sax/document.rb +45 -49
  149. data/lib/nokogiri/xml/sax/parser.rb +38 -34
  150. data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
  151. data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
  152. data/lib/nokogiri/xml/sax.rb +6 -4
  153. data/lib/nokogiri/xml/schema.rb +19 -9
  154. data/lib/nokogiri/xml/searchable.rb +112 -72
  155. data/lib/nokogiri/xml/syntax_error.rb +6 -4
  156. data/lib/nokogiri/xml/text.rb +2 -0
  157. data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
  158. data/lib/nokogiri/xml/xpath.rb +15 -4
  159. data/lib/nokogiri/xml/xpath_context.rb +3 -3
  160. data/lib/nokogiri/xml.rb +38 -37
  161. data/lib/nokogiri/xslt/stylesheet.rb +3 -1
  162. data/lib/nokogiri/xslt.rb +29 -20
  163. data/lib/nokogiri.rb +49 -65
  164. data/lib/xsd/xmlparser/nokogiri.rb +26 -24
  165. data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
  166. data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
  167. data/patches/libxml2/{0004-libxml2.la-is-in-top_builddir.patch → 0003-libxml2.la-is-in-top_builddir.patch} +1 -1
  168. data/patches/libxml2/0004-use-glibc-strlen.patch +53 -0
  169. data/patches/libxml2/0005-avoid-isnan-isinf.patch +81 -0
  170. data/patches/libxml2/0006-update-automake-files-for-arm64.patch +3040 -0
  171. data/patches/libxml2/0008-htmlParseComment-handle-abruptly-closed-comments.patch +61 -0
  172. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  173. data/patches/libxslt/0001-update-automake-files-for-arm64.patch +3037 -0
  174. data/ports/archives/libxml2-2.9.14.tar.xz +0 -0
  175. data/ports/archives/libxslt-1.1.35.tar.xz +0 -0
  176. metadata +196 -140
  177. data/ext/nokogiri/html_document.c +0 -170
  178. data/ext/nokogiri/html_document.h +0 -10
  179. data/ext/nokogiri/html_element_description.c +0 -279
  180. data/ext/nokogiri/html_element_description.h +0 -10
  181. data/ext/nokogiri/html_entity_lookup.c +0 -32
  182. data/ext/nokogiri/html_entity_lookup.h +0 -8
  183. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  184. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  185. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  186. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  187. data/ext/nokogiri/xml_attr.h +0 -9
  188. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  189. data/ext/nokogiri/xml_cdata.h +0 -9
  190. data/ext/nokogiri/xml_comment.h +0 -9
  191. data/ext/nokogiri/xml_document.h +0 -23
  192. data/ext/nokogiri/xml_document_fragment.h +0 -10
  193. data/ext/nokogiri/xml_dtd.h +0 -10
  194. data/ext/nokogiri/xml_element_content.h +0 -10
  195. data/ext/nokogiri/xml_element_decl.h +0 -9
  196. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  197. data/ext/nokogiri/xml_entity_decl.h +0 -10
  198. data/ext/nokogiri/xml_entity_reference.h +0 -9
  199. data/ext/nokogiri/xml_io.c +0 -61
  200. data/ext/nokogiri/xml_io.h +0 -11
  201. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  202. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  203. data/ext/nokogiri/xml_namespace.h +0 -14
  204. data/ext/nokogiri/xml_node.h +0 -13
  205. data/ext/nokogiri/xml_node_set.h +0 -12
  206. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  207. data/ext/nokogiri/xml_reader.h +0 -10
  208. data/ext/nokogiri/xml_relax_ng.h +0 -9
  209. data/ext/nokogiri/xml_sax_parser.h +0 -39
  210. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  211. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  212. data/ext/nokogiri/xml_schema.h +0 -9
  213. data/ext/nokogiri/xml_syntax_error.h +0 -13
  214. data/ext/nokogiri/xml_text.h +0 -9
  215. data/ext/nokogiri/xml_xpath_context.h +0 -10
  216. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  217. data/lib/nokogiri/html/document_fragment.rb +0 -49
  218. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  219. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  220. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  221. data/patches/libxml2/0005-Fix-infinite-loop-in-xmlStringLenDecodeEntities.patch +0 -32
  222. data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
  223. data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
@@ -1,36 +1,44 @@
1
- #include <xml_node.h>
1
+ #include <nokogiri.h>
2
+
3
+ // :stopdoc:
4
+
5
+ VALUE cNokogiriXmlNode ;
6
+ static ID id_decorate, id_decorate_bang;
7
+
8
+ typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
2
9
 
3
- static ID decorate, decorate_bang;
4
10
 
5
11
  #ifdef DEBUG
6
- static void debug_node_dealloc(xmlNodePtr x)
12
+ static void
13
+ _xml_node_dealloc(xmlNodePtr x)
7
14
  {
8
15
  NOKOGIRI_DEBUG_START(x)
9
16
  NOKOGIRI_DEBUG_END(x)
10
17
  }
11
18
  #else
12
- # define debug_node_dealloc 0
19
+ # define _xml_node_dealloc 0
13
20
  #endif
14
21
 
15
- static void mark(xmlNodePtr node)
22
+
23
+ static void
24
+ _xml_node_mark(xmlNodePtr node)
16
25
  {
17
26
  xmlDocPtr doc = node->doc;
18
- if(doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
19
- if(DOC_RUBY_OBJECT_TEST(doc)) {
27
+ if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
28
+ if (DOC_RUBY_OBJECT_TEST(doc)) {
20
29
  rb_gc_mark(DOC_RUBY_OBJECT(doc));
21
30
  }
22
- } else if(node->doc->_private) {
31
+ } else if (node->doc->_private) {
23
32
  rb_gc_mark((VALUE)doc->_private);
24
33
  }
25
34
  }
26
35
 
27
- /* :nodoc: */
28
- typedef xmlNodePtr (*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
29
36
 
30
- /* :nodoc: */
31
- static void relink_namespace(xmlNodePtr reparented)
37
+ static void
38
+ relink_namespace(xmlNodePtr reparented)
32
39
  {
33
40
  xmlNodePtr child;
41
+ xmlAttrPtr attr;
34
42
 
35
43
  if (reparented->type != XML_ATTRIBUTE_NODE &&
36
44
  reparented->type != XML_ELEMENT_NODE) { return; }
@@ -42,7 +50,7 @@ static void relink_namespace(xmlNodePtr reparented)
42
50
  name = xmlSplitQName2(reparented->name, &prefix);
43
51
 
44
52
  if (reparented->type == XML_ATTRIBUTE_NODE) {
45
- if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) {
53
+ if (prefix == NULL || strcmp((char *)prefix, XMLNS_PREFIX) == 0) {
46
54
  xmlFree(name);
47
55
  xmlFree(prefix);
48
56
  return;
@@ -64,7 +72,9 @@ static void relink_namespace(xmlNodePtr reparented)
64
72
  if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
65
73
 
66
74
  /* Make sure that our reparented node has the correct namespaces */
67
- if (!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent) {
75
+ if (!reparented->ns &&
76
+ (reparented->doc != (xmlDocPtr)reparented->parent) &&
77
+ (rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
68
78
  xmlSetNs(reparented, reparented->parent->ns);
69
79
  }
70
80
 
@@ -87,7 +97,7 @@ static void relink_namespace(xmlNodePtr reparented)
87
97
  } else {
88
98
  reparented->nsDef = curr->next;
89
99
  }
90
- nokogiri_root_nsdef(curr, reparented->doc);
100
+ noko_xml_document_pin_namespace(curr, reparented->doc);
91
101
  } else {
92
102
  prev = curr;
93
103
  }
@@ -127,16 +137,19 @@ static void relink_namespace(xmlNodePtr reparented)
127
137
  }
128
138
 
129
139
  if (reparented->type == XML_ELEMENT_NODE) {
130
- child = (xmlNodePtr)((xmlElementPtr)reparented)->attributes;
131
- while(NULL != child) {
132
- relink_namespace(child);
133
- child = child->next;
140
+ attr = reparented->properties;
141
+ while (NULL != attr) {
142
+ relink_namespace((xmlNodePtr)attr);
143
+ attr = attr->next;
134
144
  }
135
145
  }
136
146
  }
137
147
 
138
- /* :nodoc: */
139
- static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
148
+
149
+ /* internal function meant to wrap xmlReplaceNode
150
+ and fix some issues we have with libxml2 merging nodes */
151
+ static xmlNodePtr
152
+ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
140
153
  {
141
154
  xmlNodePtr retval ;
142
155
 
@@ -159,17 +172,29 @@ static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
159
172
  return retval ;
160
173
  }
161
174
 
162
- /* :nodoc: */
163
- static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
175
+
176
+ static void
177
+ raise_if_ancestor_of_self(xmlNodePtr self)
178
+ {
179
+ for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
180
+ if (self == ancestor) {
181
+ rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
182
+ }
183
+ }
184
+ }
185
+
186
+
187
+ static VALUE
188
+ reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
164
189
  {
165
190
  VALUE reparented_obj ;
166
- xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text, parent ;
191
+ xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ;
167
192
  int original_ns_prefix_is_default = 0 ;
168
193
 
169
- if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
194
+ if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
170
195
  rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
171
196
  }
172
- if(rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
197
+ if (rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
173
198
  rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
174
199
  }
175
200
 
@@ -190,66 +215,66 @@ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_rep
190
215
 
191
216
  if (parent) {
192
217
  switch (parent->type) {
193
- case XML_DOCUMENT_NODE:
194
- case XML_HTML_DOCUMENT_NODE:
195
- switch (reparentee->type) {
196
- case XML_ELEMENT_NODE:
197
- case XML_PI_NODE:
198
- case XML_COMMENT_NODE:
199
- case XML_DOCUMENT_TYPE_NODE:
200
- /*
201
- * The DOM specification says no to adding text-like nodes
202
- * directly to a document, but we allow it for compatibility.
203
- */
204
- case XML_TEXT_NODE:
205
- case XML_CDATA_SECTION_NODE:
206
- case XML_ENTITY_REF_NODE:
207
- goto ok;
208
- default:
218
+ case XML_DOCUMENT_NODE:
219
+ case XML_HTML_DOCUMENT_NODE:
220
+ switch (reparentee->type) {
221
+ case XML_ELEMENT_NODE:
222
+ case XML_PI_NODE:
223
+ case XML_COMMENT_NODE:
224
+ case XML_DOCUMENT_TYPE_NODE:
225
+ /*
226
+ * The DOM specification says no to adding text-like nodes
227
+ * directly to a document, but we allow it for compatibility.
228
+ */
229
+ case XML_TEXT_NODE:
230
+ case XML_CDATA_SECTION_NODE:
231
+ case XML_ENTITY_REF_NODE:
232
+ goto ok;
233
+ default:
234
+ break;
235
+ }
209
236
  break;
210
- }
211
- break;
212
- case XML_DOCUMENT_FRAG_NODE:
213
- case XML_ENTITY_REF_NODE:
214
- case XML_ELEMENT_NODE:
215
- switch (reparentee->type) {
216
- case XML_ELEMENT_NODE:
217
- case XML_PI_NODE:
218
- case XML_COMMENT_NODE:
219
- case XML_TEXT_NODE:
220
- case XML_CDATA_SECTION_NODE:
237
+ case XML_DOCUMENT_FRAG_NODE:
221
238
  case XML_ENTITY_REF_NODE:
222
- goto ok;
223
- default:
239
+ case XML_ELEMENT_NODE:
240
+ switch (reparentee->type) {
241
+ case XML_ELEMENT_NODE:
242
+ case XML_PI_NODE:
243
+ case XML_COMMENT_NODE:
244
+ case XML_TEXT_NODE:
245
+ case XML_CDATA_SECTION_NODE:
246
+ case XML_ENTITY_REF_NODE:
247
+ goto ok;
248
+ default:
249
+ break;
250
+ }
251
+ break;
252
+ case XML_ATTRIBUTE_NODE:
253
+ switch (reparentee->type) {
254
+ case XML_TEXT_NODE:
255
+ case XML_ENTITY_REF_NODE:
256
+ goto ok;
257
+ default:
258
+ break;
259
+ }
224
260
  break;
225
- }
226
- break;
227
- case XML_ATTRIBUTE_NODE:
228
- switch (reparentee->type) {
229
261
  case XML_TEXT_NODE:
230
- case XML_ENTITY_REF_NODE:
231
- goto ok;
262
+ /*
263
+ * xmlAddChild() breaks the DOM specification in that it allows
264
+ * adding a text node to another, in which case text nodes are
265
+ * coalesced, but since our JRuby version does not support such
266
+ * operation, we should inhibit it.
267
+ */
268
+ break;
232
269
  default:
233
270
  break;
234
- }
235
- break;
236
- case XML_TEXT_NODE:
237
- /*
238
- * xmlAddChild() breaks the DOM specification in that it allows
239
- * adding a text node to another, in which case text nodes are
240
- * coalesced, but since our JRuby version does not support such
241
- * operation, we should inhibit it.
242
- */
243
- break;
244
- default:
245
- break;
246
271
  }
247
272
 
248
273
  rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj));
249
274
  }
250
275
 
251
276
  ok:
252
- xmlUnlinkNode(reparentee);
277
+ original_reparentee = reparentee;
253
278
 
254
279
  if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
255
280
  /*
@@ -290,7 +315,7 @@ ok:
290
315
  original_ns_prefix_is_default = 1;
291
316
  }
292
317
 
293
- nokogiri_root_node(reparentee);
318
+ noko_xml_document_pin_node(reparentee);
294
319
 
295
320
  if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
296
321
  rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
@@ -301,11 +326,13 @@ ok:
301
326
  * issue #391, where new node's prefix may become the string "default"
302
327
  * see libxml2 tree.c xmlNewReconciliedNs which implements this behavior.
303
328
  */
304
- xmlFree(reparentee->ns->prefix);
329
+ xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix));
305
330
  reparentee->ns->prefix = NULL;
306
331
  }
307
332
  }
308
333
 
334
+ xmlUnlinkNode(original_reparentee);
335
+
309
336
  if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling
310
337
  && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
311
338
  /*
@@ -330,12 +357,12 @@ ok:
330
357
  new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
331
358
 
332
359
  xmlUnlinkNode(next_text);
333
- nokogiri_root_node(next_text);
360
+ noko_xml_document_pin_node(next_text);
334
361
 
335
362
  xmlAddNextSibling(pivot, new_next_text);
336
363
  }
337
364
 
338
- if(!(reparented = (*prf)(pivot, reparentee))) {
365
+ if (!(reparented = (*prf)(pivot, reparentee))) {
339
366
  rb_raise(rb_eRuntimeError, "Could not reparent node");
340
367
  }
341
368
 
@@ -345,24 +372,397 @@ ok:
345
372
  * adjacent text nodes.
346
373
  */
347
374
  DATA_PTR(reparentee_obj) = reparented ;
375
+ reparented_obj = noko_xml_node_wrap(Qnil, reparented);
348
376
 
349
- relink_namespace(reparented);
377
+ rb_funcall(reparented_obj, id_decorate_bang, 0);
350
378
 
351
- reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
379
+ /* if we've created a cycle, raise an exception */
380
+ raise_if_ancestor_of_self(reparented);
352
381
 
353
- rb_funcall(reparented_obj, decorate_bang, 0);
382
+ relink_namespace(reparented);
354
383
 
355
384
  return reparented_obj ;
356
385
  }
357
386
 
387
+ // :startdoc:
358
388
 
359
389
  /*
360
- * call-seq:
361
- * document
390
+ * :call-seq:
391
+ * add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
392
+ * add_namespace(prefix, href) → Nokogiri::XML::Namespace
393
+ *
394
+ * :category: Manipulating Document Structure
395
+ *
396
+ * Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
397
+ * included an attribute "xmlns:prefix=href".
398
+ *
399
+ * A default namespace definition for this node can be added by passing +nil+ for +prefix+.
400
+ *
401
+ * [Parameters]
402
+ * - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
403
+ * - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
404
+ *
405
+ * [Returns] The new Nokogiri::XML::Namespace
406
+ *
407
+ * *Example:* adding a non-default namespace definition
408
+ *
409
+ * doc = Nokogiri::XML("<store><inventory></inventory></store>")
410
+ * inventory = doc.at_css("inventory")
411
+ * inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
412
+ * inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
413
+ * inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
414
+ * doc.to_xml
415
+ * # => "<?xml version=\"1.0\"?>\n" +
416
+ * # "<store>\n" +
417
+ * # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
418
+ * # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
419
+ * # " </inventory>\n" +
420
+ * # "</store>\n"
421
+ *
422
+ * *Example:* adding a default namespace definition
423
+ *
424
+ * doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
425
+ * doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
426
+ * doc.to_xml
427
+ * # => "<?xml version=\"1.0\"?>\n" +
428
+ * # "<store>\n" +
429
+ * # " <inventory>\n" +
430
+ * # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
431
+ * # " </inventory>\n" +
432
+ * # "</store>\n"
433
+ *
434
+ */
435
+ static VALUE
436
+ rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
437
+ {
438
+ xmlNodePtr c_node, element;
439
+ xmlNsPtr c_namespace;
440
+ const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
441
+
442
+ Data_Get_Struct(rb_node, xmlNode, c_node);
443
+ element = c_node ;
444
+
445
+ c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
446
+
447
+ if (!c_namespace) {
448
+ if (c_node->type != XML_ELEMENT_NODE) {
449
+ element = c_node->parent;
450
+ }
451
+ c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
452
+ }
453
+
454
+ if (!c_namespace) {
455
+ return Qnil ;
456
+ }
457
+
458
+ if (NIL_P(rb_prefix) || c_node != element) {
459
+ xmlSetNs(c_node, c_namespace);
460
+ }
461
+
462
+ return noko_xml_namespace_wrap(c_namespace, c_node->doc);
463
+ }
464
+
465
+
466
+ /*
467
+ * :call-seq: attribute(name) → Nokogiri::XML::Attr
468
+ *
469
+ * :category: Working With Node Attributes
470
+ *
471
+ * [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
472
+ *
473
+ * ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
474
+ * used to find a matching attribute. In case of a simple name collision, only one of the matching
475
+ * attributes will be returned. In this case, you will need to use #attribute_with_ns.
476
+ *
477
+ * *Example:*
478
+ *
479
+ * doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
480
+ * child = doc.at_css("child")
481
+ * child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
482
+ * child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
483
+ *
484
+ * *Example* showing that namespaced attributes will not be returned:
485
+ *
486
+ * ⚠ Note that only one of the two matching attributes is returned.
487
+ *
488
+ * doc = Nokogiri::XML(<<~EOF)
489
+ * <root xmlns:width='http://example.com/widths'
490
+ * xmlns:height='http://example.com/heights'>
491
+ * <child width:size='broad' height:size='tall'/>
492
+ * </root>
493
+ * EOF
494
+ * doc.at_css("child").attribute("size")
495
+ * # => #(Attr:0x550 {
496
+ * # name = "size",
497
+ * # namespace = #(Namespace:0x564 {
498
+ * # prefix = "width",
499
+ * # href = "http://example.com/widths"
500
+ * # }),
501
+ * # value = "broad"
502
+ * # })
503
+ */
504
+ static VALUE
505
+ rb_xml_node_attribute(VALUE self, VALUE name)
506
+ {
507
+ xmlNodePtr node;
508
+ xmlAttrPtr prop;
509
+ Data_Get_Struct(self, xmlNode, node);
510
+ prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
511
+
512
+ if (! prop) { return Qnil; }
513
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
514
+ }
515
+
516
+
517
+ /*
518
+ * :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
519
+ *
520
+ * :category: Working With Node Attributes
521
+ *
522
+ * [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
523
+ *
524
+ * Note that this is the preferred alternative to #attributes when the simple
525
+ * (non-namespace-prefixed) attribute names may collide.
526
+ *
527
+ * *Example:*
528
+ *
529
+ * Contrast this with the colliding-name example from #attributes.
530
+ *
531
+ * doc = Nokogiri::XML(<<~EOF)
532
+ * <root xmlns:width='http://example.com/widths'
533
+ * xmlns:height='http://example.com/heights'>
534
+ * <child width:size='broad' height:size='tall'/>
535
+ * </root>
536
+ * EOF
537
+ * doc.at_css("child").attribute_nodes
538
+ * # => [#(Attr:0x550 {
539
+ * # name = "size",
540
+ * # namespace = #(Namespace:0x564 {
541
+ * # prefix = "width",
542
+ * # href = "http://example.com/widths"
543
+ * # }),
544
+ * # value = "broad"
545
+ * # }),
546
+ * # #(Attr:0x578 {
547
+ * # name = "size",
548
+ * # namespace = #(Namespace:0x58c {
549
+ * # prefix = "height",
550
+ * # href = "http://example.com/heights"
551
+ * # }),
552
+ * # value = "tall"
553
+ * # })]
554
+ */
555
+ static VALUE
556
+ rb_xml_node_attribute_nodes(VALUE rb_node)
557
+ {
558
+ xmlNodePtr c_node;
559
+
560
+ Data_Get_Struct(rb_node, xmlNode, c_node);
561
+
562
+ return noko_xml_node_attrs(c_node);
563
+ }
564
+
565
+
566
+ /*
567
+ * :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
568
+ *
569
+ * :category: Working With Node Attributes
570
+ *
571
+ * [Returns]
572
+ * Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
573
+ *
574
+ * [Parameters]
575
+ * - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
576
+ * - +namespace+ (String): the URI of the attribute's namespace
577
+ *
578
+ * See related: #attribute
579
+ *
580
+ * *Example:*
581
+ *
582
+ * doc = Nokogiri::XML(<<~EOF)
583
+ * <root xmlns:width='http://example.com/widths'
584
+ * xmlns:height='http://example.com/heights'>
585
+ * <child width:size='broad' height:size='tall'/>
586
+ * </root>
587
+ * EOF
588
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
589
+ * # => #(Attr:0x550 {
590
+ * # name = "size",
591
+ * # namespace = #(Namespace:0x564 {
592
+ * # prefix = "width",
593
+ * # href = "http://example.com/widths"
594
+ * # }),
595
+ * # value = "broad"
596
+ * # })
597
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
598
+ * # => #(Attr:0x578 {
599
+ * # name = "size",
600
+ * # namespace = #(Namespace:0x58c {
601
+ * # prefix = "height",
602
+ * # href = "http://example.com/heights"
603
+ * # }),
604
+ * # value = "tall"
605
+ * # })
606
+ */
607
+ static VALUE
608
+ rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
609
+ {
610
+ xmlNodePtr node;
611
+ xmlAttrPtr prop;
612
+ Data_Get_Struct(self, xmlNode, node);
613
+ prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
614
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
615
+
616
+ if (! prop) { return Qnil; }
617
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
618
+ }
619
+
620
+
621
+
622
+ /*
623
+ * call-seq: blank? → Boolean
624
+ *
625
+ * [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
626
+ *
627
+ * *Example:*
628
+ *
629
+ * Nokogiri("<root><child/></root>").root.child.blank? # => false
630
+ * Nokogiri("<root>\t \n</root>").root.child.blank? # => true
631
+ * Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
632
+ * Nokogiri("<root>not-blank</root>").root.child
633
+ * .tap { |n| n.content = "" }.blank # => true
634
+ */
635
+ static VALUE
636
+ rb_xml_node_blank_eh(VALUE self)
637
+ {
638
+ xmlNodePtr node;
639
+ Data_Get_Struct(self, xmlNode, node);
640
+ return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
641
+ }
642
+
643
+
644
+ /*
645
+ * :call-seq: child() → Nokogiri::XML::Node
646
+ *
647
+ * :category: Traversing Document Structure
648
+ *
649
+ * [Returns] First of this node's children, or +nil+ if there are no children
650
+ *
651
+ * This is a convenience method and is equivalent to:
652
+ *
653
+ * node.children.first
654
+ *
655
+ * See related: #children
656
+ */
657
+ static VALUE
658
+ rb_xml_node_child(VALUE self)
659
+ {
660
+ xmlNodePtr node, child;
661
+ Data_Get_Struct(self, xmlNode, node);
662
+
663
+ child = node->children;
664
+ if (!child) { return Qnil; }
665
+
666
+ return noko_xml_node_wrap(Qnil, child);
667
+ }
668
+
669
+
670
+ /*
671
+ * :call-seq: children() → Nokogiri::XML::NodeSet
672
+ *
673
+ * :category: Traversing Document Structure
674
+ *
675
+ * [Returns] Nokogiri::XML::NodeSet containing this node's children.
676
+ */
677
+ static VALUE
678
+ rb_xml_node_children(VALUE self)
679
+ {
680
+ xmlNodePtr node;
681
+ xmlNodePtr child;
682
+ xmlNodeSetPtr set;
683
+ VALUE document;
684
+ VALUE node_set;
685
+
686
+ Data_Get_Struct(self, xmlNode, node);
687
+
688
+ child = node->children;
689
+ set = xmlXPathNodeSetCreate(child);
690
+
691
+ document = DOC_RUBY_OBJECT(node->doc);
692
+
693
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
694
+
695
+ child = child->next;
696
+ while (NULL != child) {
697
+ xmlXPathNodeSetAddUnique(set, child);
698
+ child = child->next;
699
+ }
700
+
701
+ node_set = noko_xml_node_set_wrap(set, document);
702
+
703
+ return node_set;
704
+ }
705
+
706
+
707
+ /*
708
+ * :call-seq:
709
+ * content() → String
710
+ * inner_text() → String
711
+ * text() → String
712
+ * to_str() → String
713
+ *
714
+ * [Returns]
715
+ * Contents of all the text nodes in this node's subtree, concatenated together into a single
716
+ * String.
717
+ *
718
+ * ⚠ Note that entities will _always_ be expanded in the returned String.
719
+ *
720
+ * See related: #inner_html
721
+ *
722
+ * *Example* of how entities are handled:
723
+ *
724
+ * Note that <tt>&lt;</tt> becomes <tt><</tt> in the returned String.
725
+ *
726
+ * doc = Nokogiri::XML.fragment("<child>a &lt; b</child>")
727
+ * doc.at_css("child").content
728
+ * # => "a < b"
729
+ *
730
+ * *Example* of how a subtree is handled:
731
+ *
732
+ * Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
733
+ * concatenated into a single string.
734
+ *
735
+ * doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
736
+ * doc.at_css("child").content
737
+ * # => "first second"
738
+ */
739
+ static VALUE
740
+ rb_xml_node_content(VALUE self)
741
+ {
742
+ xmlNodePtr node;
743
+ xmlChar *content;
744
+
745
+ Data_Get_Struct(self, xmlNode, node);
746
+
747
+ content = xmlNodeGetContent(node);
748
+ if (content) {
749
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
750
+ xmlFree(content);
751
+ return rval;
752
+ }
753
+ return Qnil;
754
+ }
755
+
756
+
757
+ /*
758
+ * :call-seq: document() → Nokogiri::XML::Document
362
759
  *
363
- * Get the document for this Node
760
+ * :category: Traversing Document Structure
761
+ *
762
+ * [Returns] Parent Nokogiri::XML::Document for this node
364
763
  */
365
- static VALUE document(VALUE self)
764
+ static VALUE
765
+ rb_xml_node_document(VALUE self)
366
766
  {
367
767
  xmlNodePtr node;
368
768
  Data_Get_Struct(self, xmlNode, node);
@@ -370,12 +770,14 @@ static VALUE document(VALUE self)
370
770
  }
371
771
 
372
772
  /*
373
- * call-seq:
374
- * pointer_id
773
+ * :call-seq: pointer_id() → Integer
375
774
  *
376
- * Get the internal pointer number
775
+ * [Returns]
776
+ * A unique id for this node based on the internal memory structures. This method is used by #==
777
+ * to determine node identity.
377
778
  */
378
- static VALUE pointer_id(VALUE self)
779
+ static VALUE
780
+ rb_xml_node_pointer_id(VALUE self)
379
781
  {
380
782
  xmlNodePtr node;
381
783
  Data_Get_Struct(self, xmlNode, node);
@@ -384,12 +786,12 @@ static VALUE pointer_id(VALUE self)
384
786
  }
385
787
 
386
788
  /*
387
- * call-seq:
388
- * encode_special_chars(string)
789
+ * :call-seq: encode_special_chars(string) → String
389
790
  *
390
791
  * Encode any special characters in +string+
391
792
  */
392
- static VALUE encode_special_chars(VALUE self, VALUE string)
793
+ static VALUE
794
+ encode_special_chars(VALUE self, VALUE string)
393
795
  {
394
796
  xmlNodePtr node;
395
797
  xmlChar *encoded;
@@ -408,8 +810,8 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
408
810
  }
409
811
 
410
812
  /*
411
- * call-seq:
412
- * create_internal_subset(name, external_id, system_id)
813
+ * :call-seq:
814
+ * create_internal_subset(name, external_id, system_id)
413
815
  *
414
816
  * Create the internal subset of a document.
415
817
  *
@@ -419,7 +821,8 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
419
821
  * doc.create_internal_subset("chapter", nil, "chapter.dtd")
420
822
  * # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
421
823
  */
422
- static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
824
+ static VALUE
825
+ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
423
826
  {
424
827
  xmlNodePtr node;
425
828
  xmlDocPtr doc;
@@ -429,7 +832,7 @@ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, V
429
832
 
430
833
  doc = node->doc;
431
834
 
432
- if(xmlGetIntSubset(doc)) {
835
+ if (xmlGetIntSubset(doc)) {
433
836
  rb_raise(rb_eRuntimeError, "Document already has an internal subset");
434
837
  }
435
838
 
@@ -440,18 +843,19 @@ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, V
440
843
  NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
441
844
  );
442
845
 
443
- if(!dtd) { return Qnil; }
846
+ if (!dtd) { return Qnil; }
444
847
 
445
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
848
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
446
849
  }
447
850
 
448
851
  /*
449
- * call-seq:
450
- * create_external_subset(name, external_id, system_id)
852
+ * :call-seq:
853
+ * create_external_subset(name, external_id, system_id)
451
854
  *
452
855
  * Create an external subset
453
856
  */
454
- static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
857
+ static VALUE
858
+ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
455
859
  {
456
860
  xmlNodePtr node;
457
861
  xmlDocPtr doc;
@@ -461,7 +865,7 @@ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, V
461
865
 
462
866
  doc = node->doc;
463
867
 
464
- if(doc->extSubset) {
868
+ if (doc->extSubset) {
465
869
  rb_raise(rb_eRuntimeError, "Document already has an external subset");
466
870
  }
467
871
 
@@ -472,18 +876,19 @@ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, V
472
876
  NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
473
877
  );
474
878
 
475
- if(!dtd) { return Qnil; }
879
+ if (!dtd) { return Qnil; }
476
880
 
477
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
881
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
478
882
  }
479
883
 
480
884
  /*
481
- * call-seq:
482
- * external_subset
885
+ * :call-seq:
886
+ * external_subset()
483
887
  *
484
888
  * Get the external subset
485
889
  */
486
- static VALUE external_subset(VALUE self)
890
+ static VALUE
891
+ external_subset(VALUE self)
487
892
  {
488
893
  xmlNodePtr node;
489
894
  xmlDocPtr doc;
@@ -491,23 +896,24 @@ static VALUE external_subset(VALUE self)
491
896
 
492
897
  Data_Get_Struct(self, xmlNode, node);
493
898
 
494
- if(!node->doc) { return Qnil; }
899
+ if (!node->doc) { return Qnil; }
495
900
 
496
901
  doc = node->doc;
497
902
  dtd = doc->extSubset;
498
903
 
499
- if(!dtd) { return Qnil; }
904
+ if (!dtd) { return Qnil; }
500
905
 
501
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
906
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
502
907
  }
503
908
 
504
909
  /*
505
- * call-seq:
506
- * internal_subset
910
+ * :call-seq:
911
+ * internal_subset()
507
912
  *
508
913
  * Get the internal subset
509
914
  */
510
- static VALUE internal_subset(VALUE self)
915
+ static VALUE
916
+ internal_subset(VALUE self)
511
917
  {
512
918
  xmlNodePtr node;
513
919
  xmlDocPtr doc;
@@ -515,29 +921,33 @@ static VALUE internal_subset(VALUE self)
515
921
 
516
922
  Data_Get_Struct(self, xmlNode, node);
517
923
 
518
- if(!node->doc) { return Qnil; }
924
+ if (!node->doc) { return Qnil; }
519
925
 
520
926
  doc = node->doc;
521
927
  dtd = xmlGetIntSubset(doc);
522
928
 
523
- if(!dtd) { return Qnil; }
929
+ if (!dtd) { return Qnil; }
524
930
 
525
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
931
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
526
932
  }
527
933
 
528
934
  /*
529
- * call-seq:
530
- * dup
531
- * dup(depth)
532
- * dup(depth, new_parent_doc)
935
+ * :call-seq:
936
+ * dup → Nokogiri::XML::Node
937
+ * dup(depth) → Nokogiri::XML::Node
938
+ * dup(depth, new_parent_doc) → Nokogiri::XML::Node
533
939
  *
534
940
  * Copy this node.
535
- * An optional depth may be passed in. 0 is a shallow copy, 1 (the default) is a deep copy.
536
- * An optional new_parent_doc may also be passed in, which will be the new
537
- * node's parent document. Defaults to the current node's document.
538
- * current document.
941
+ *
942
+ * [Parameters]
943
+ * - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
944
+ * - +new_parent_doc+
945
+ * The new node's parent Document. Defaults to the this node's document.
946
+ *
947
+ * [Returns] The new Nokgiri::XML::Node
539
948
  */
540
- static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
949
+ static VALUE
950
+ duplicate_node(int argc, VALUE *argv, VALUE self)
541
951
  {
542
952
  VALUE r_level, r_new_parent_doc;
543
953
  int level;
@@ -561,40 +971,29 @@ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
561
971
  }
562
972
 
563
973
  dup = xmlDocCopyNode(node, new_parent_doc, level);
564
- if(dup == NULL) { return Qnil; }
974
+ if (dup == NULL) { return Qnil; }
565
975
 
566
- nokogiri_root_node(dup);
976
+ noko_xml_document_pin_node(dup);
567
977
 
568
- return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
978
+ return noko_xml_node_wrap(rb_obj_class(self), dup);
569
979
  }
570
980
 
571
981
  /*
572
- * call-seq:
573
- * unlink
982
+ * :call-seq:
983
+ * unlink() → self
574
984
  *
575
985
  * Unlink this node from its current context.
576
986
  */
577
- static VALUE unlink_node(VALUE self)
987
+ static VALUE
988
+ unlink_node(VALUE self)
578
989
  {
579
990
  xmlNodePtr node;
580
991
  Data_Get_Struct(self, xmlNode, node);
581
992
  xmlUnlinkNode(node);
582
- nokogiri_root_node(node);
993
+ noko_xml_document_pin_node(node);
583
994
  return self;
584
995
  }
585
996
 
586
- /*
587
- * call-seq:
588
- * blank?
589
- *
590
- * Is this node blank?
591
- */
592
- static VALUE blank_eh(VALUE self)
593
- {
594
- xmlNodePtr node;
595
- Data_Get_Struct(self, xmlNode, node);
596
- return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
597
- }
598
997
 
599
998
  /*
600
999
  * call-seq:
@@ -602,15 +1001,16 @@ static VALUE blank_eh(VALUE self)
602
1001
  *
603
1002
  * Returns the next sibling node
604
1003
  */
605
- static VALUE next_sibling(VALUE self)
1004
+ static VALUE
1005
+ next_sibling(VALUE self)
606
1006
  {
607
1007
  xmlNodePtr node, sibling;
608
1008
  Data_Get_Struct(self, xmlNode, node);
609
1009
 
610
1010
  sibling = node->next;
611
- if(!sibling) { return Qnil; }
1011
+ if (!sibling) { return Qnil; }
612
1012
 
613
- return Nokogiri_wrap_xml_node(Qnil, sibling) ;
1013
+ return noko_xml_node_wrap(Qnil, sibling) ;
614
1014
  }
615
1015
 
616
1016
  /*
@@ -619,15 +1019,16 @@ static VALUE next_sibling(VALUE self)
619
1019
  *
620
1020
  * Returns the previous sibling node
621
1021
  */
622
- static VALUE previous_sibling(VALUE self)
1022
+ static VALUE
1023
+ previous_sibling(VALUE self)
623
1024
  {
624
1025
  xmlNodePtr node, sibling;
625
1026
  Data_Get_Struct(self, xmlNode, node);
626
1027
 
627
1028
  sibling = node->prev;
628
- if(!sibling) { return Qnil; }
1029
+ if (!sibling) { return Qnil; }
629
1030
 
630
- return Nokogiri_wrap_xml_node(Qnil, sibling);
1031
+ return noko_xml_node_wrap(Qnil, sibling);
631
1032
  }
632
1033
 
633
1034
  /*
@@ -636,15 +1037,16 @@ static VALUE previous_sibling(VALUE self)
636
1037
  *
637
1038
  * Returns the next Nokogiri::XML::Element type sibling node.
638
1039
  */
639
- static VALUE next_element(VALUE self)
1040
+ static VALUE
1041
+ next_element(VALUE self)
640
1042
  {
641
1043
  xmlNodePtr node, sibling;
642
1044
  Data_Get_Struct(self, xmlNode, node);
643
1045
 
644
1046
  sibling = xmlNextElementSibling(node);
645
- if(!sibling) { return Qnil; }
1047
+ if (!sibling) { return Qnil; }
646
1048
 
647
- return Nokogiri_wrap_xml_node(Qnil, sibling);
1049
+ return noko_xml_node_wrap(Qnil, sibling);
648
1050
  }
649
1051
 
650
1052
  /*
@@ -653,7 +1055,8 @@ static VALUE next_element(VALUE self)
653
1055
  *
654
1056
  * Returns the previous Nokogiri::XML::Element type sibling node.
655
1057
  */
656
- static VALUE previous_element(VALUE self)
1058
+ static VALUE
1059
+ previous_element(VALUE self)
657
1060
  {
658
1061
  xmlNodePtr node, sibling;
659
1062
  Data_Get_Struct(self, xmlNode, node);
@@ -662,73 +1065,50 @@ static VALUE previous_element(VALUE self)
662
1065
  * note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
663
1066
  */
664
1067
  sibling = node->prev;
665
- if(!sibling) { return Qnil; }
1068
+ if (!sibling) { return Qnil; }
666
1069
 
667
- while(sibling && sibling->type != XML_ELEMENT_NODE) {
1070
+ while (sibling && sibling->type != XML_ELEMENT_NODE) {
668
1071
  sibling = sibling->prev;
669
1072
  }
670
1073
 
671
- return sibling ? Nokogiri_wrap_xml_node(Qnil, sibling) : Qnil ;
1074
+ return sibling ? noko_xml_node_wrap(Qnil, sibling) : Qnil ;
672
1075
  }
673
1076
 
674
1077
  /* :nodoc: */
675
- static VALUE replace(VALUE self, VALUE new_node)
1078
+ static VALUE
1079
+ replace(VALUE self, VALUE new_node)
676
1080
  {
677
1081
  VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper);
678
1082
 
679
1083
  xmlNodePtr pivot;
680
1084
  Data_Get_Struct(self, xmlNode, pivot);
681
- nokogiri_root_node(pivot);
1085
+ noko_xml_document_pin_node(pivot);
682
1086
 
683
1087
  return reparent;
684
1088
  }
685
1089
 
686
1090
  /*
687
- * call-seq:
688
- * children
1091
+ * :call-seq:
1092
+ * element_children() → NodeSet
1093
+ * elements() → NodeSet
689
1094
  *
690
- * Get the list of children for this node as a NodeSet
691
- */
692
- static VALUE children(VALUE self)
693
- {
694
- xmlNodePtr node;
695
- xmlNodePtr child;
696
- xmlNodeSetPtr set;
697
- VALUE document;
698
- VALUE node_set;
699
-
700
- Data_Get_Struct(self, xmlNode, node);
701
-
702
- child = node->children;
703
- set = xmlXPathNodeSetCreate(child);
704
-
705
- document = DOC_RUBY_OBJECT(node->doc);
706
-
707
- if(!child) { return Nokogiri_wrap_xml_node_set(set, document); }
708
-
709
- child = child->next;
710
- while(NULL != child) {
711
- xmlXPathNodeSetAddUnique(set, child);
712
- child = child->next;
713
- }
714
-
715
- node_set = Nokogiri_wrap_xml_node_set(set, document);
716
-
717
- return node_set;
718
- }
719
-
720
- /*
721
- * call-seq:
722
- * element_children
1095
+ * [Returns]
1096
+ * The node's child elements as a NodeSet. Only children that are elements will be returned, which
1097
+ * notably excludes Text nodes.
723
1098
  *
724
- * Get the list of children for this node as a NodeSet. All nodes will be
725
- * element nodes.
1099
+ * *Example:*
726
1100
  *
727
- * Example:
1101
+ * Note that #children returns the Text node "hello" while #element_children does not.
728
1102
  *
729
- * @doc.root.element_children.all? { |x| x.element? } # => true
1103
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1104
+ * div.element_children
1105
+ * # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
1106
+ * div.children
1107
+ * # => [#<Nokogiri::XML::Text:0x64 "hello">,
1108
+ * # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
730
1109
  */
731
- static VALUE element_children(VALUE self)
1110
+ static VALUE
1111
+ rb_xml_node_element_children(VALUE self)
732
1112
  {
733
1113
  xmlNodePtr node;
734
1114
  xmlNodePtr child;
@@ -743,76 +1123,71 @@ static VALUE element_children(VALUE self)
743
1123
 
744
1124
  document = DOC_RUBY_OBJECT(node->doc);
745
1125
 
746
- if(!child) { return Nokogiri_wrap_xml_node_set(set, document); }
1126
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
747
1127
 
748
1128
  child = xmlNextElementSibling(child);
749
- while(NULL != child) {
1129
+ while (NULL != child) {
750
1130
  xmlXPathNodeSetAddUnique(set, child);
751
1131
  child = xmlNextElementSibling(child);
752
1132
  }
753
1133
 
754
- node_set = Nokogiri_wrap_xml_node_set(set, document);
1134
+ node_set = noko_xml_node_set_wrap(set, document);
755
1135
 
756
1136
  return node_set;
757
1137
  }
758
1138
 
759
1139
  /*
760
- * call-seq:
761
- * child
1140
+ * :call-seq:
1141
+ * first_element_child() → Node
762
1142
  *
763
- * Returns the child node
764
- */
765
- static VALUE child(VALUE self)
766
- {
767
- xmlNodePtr node, child;
768
- Data_Get_Struct(self, xmlNode, node);
769
-
770
- child = node->children;
771
- if(!child) { return Qnil; }
772
-
773
- return Nokogiri_wrap_xml_node(Qnil, child);
774
- }
775
-
776
- /*
777
- * call-seq:
778
- * first_element_child
1143
+ * [Returns] The first child Node that is an element.
779
1144
  *
780
- * Returns the first child node of this node that is an element.
1145
+ * *Example:*
781
1146
  *
782
- * Example:
1147
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
1148
+ * returned.
783
1149
  *
784
- * @doc.root.first_element_child.element? # => true
1150
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1151
+ * div.first_element_child
1152
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
785
1153
  */
786
- static VALUE first_element_child(VALUE self)
1154
+ static VALUE
1155
+ rb_xml_node_first_element_child(VALUE self)
787
1156
  {
788
1157
  xmlNodePtr node, child;
789
1158
  Data_Get_Struct(self, xmlNode, node);
790
1159
 
791
1160
  child = xmlFirstElementChild(node);
792
- if(!child) { return Qnil; }
1161
+ if (!child) { return Qnil; }
793
1162
 
794
- return Nokogiri_wrap_xml_node(Qnil, child);
1163
+ return noko_xml_node_wrap(Qnil, child);
795
1164
  }
796
1165
 
797
1166
  /*
798
- * call-seq:
799
- * last_element_child
1167
+ * :call-seq:
1168
+ * last_element_child() → Node
1169
+ *
1170
+ * [Returns] The last child Node that is an element.
800
1171
  *
801
- * Returns the last child node of this node that is an element.
1172
+ * *Example:*
802
1173
  *
803
- * Example:
1174
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
1175
+ * element is returned.
804
1176
  *
805
- * @doc.root.last_element_child.element? # => true
1177
+ * div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
1178
+ * div.last_element_child
1179
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
806
1180
  */
807
- static VALUE last_element_child(VALUE self)
1181
+ static VALUE
1182
+ rb_xml_node_last_element_child(VALUE self)
808
1183
  {
809
1184
  xmlNodePtr node, child;
810
1185
  Data_Get_Struct(self, xmlNode, node);
811
1186
 
812
1187
  child = xmlLastElementChild(node);
813
- if(!child) { return Qnil; }
1188
+ if (!child) { return Qnil; }
814
1189
 
815
- return Nokogiri_wrap_xml_node(Qnil, child);
1190
+ return noko_xml_node_wrap(Qnil, child);
816
1191
  }
817
1192
 
818
1193
  /*
@@ -821,11 +1196,12 @@ static VALUE last_element_child(VALUE self)
821
1196
  *
822
1197
  * Returns true if +attribute+ is set
823
1198
  */
824
- static VALUE key_eh(VALUE self, VALUE attribute)
1199
+ static VALUE
1200
+ key_eh(VALUE self, VALUE attribute)
825
1201
  {
826
1202
  xmlNodePtr node;
827
1203
  Data_Get_Struct(self, xmlNode, node);
828
- if(xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
1204
+ if (xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
829
1205
  return Qtrue;
830
1206
  }
831
1207
  return Qfalse;
@@ -837,12 +1213,13 @@ static VALUE key_eh(VALUE self, VALUE attribute)
837
1213
  *
838
1214
  * Returns true if +attribute+ is set with +namespace+
839
1215
  */
840
- static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
1216
+ static VALUE
1217
+ namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
841
1218
  {
842
1219
  xmlNodePtr node;
843
1220
  Data_Get_Struct(self, xmlNode, node);
844
- if(xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
845
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
1221
+ if (xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
1222
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
846
1223
  return Qtrue;
847
1224
  }
848
1225
  return Qfalse;
@@ -854,7 +1231,8 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
854
1231
  *
855
1232
  * Set the +property+ to +value+
856
1233
  */
857
- static VALUE set(VALUE self, VALUE property, VALUE value)
1234
+ static VALUE
1235
+ set(VALUE self, VALUE property, VALUE value)
858
1236
  {
859
1237
  xmlNodePtr node, cur;
860
1238
  xmlAttrPtr prop;
@@ -867,13 +1245,13 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
867
1245
  * We can avoid this by unlinking these nodes first.
868
1246
  */
869
1247
  if (node->type != XML_ELEMENT_NODE) {
870
- return(Qnil);
1248
+ return (Qnil);
871
1249
  }
872
1250
  prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property));
873
1251
  if (prop && prop->children) {
874
1252
  for (cur = prop->children; cur; cur = cur->next) {
875
1253
  if (cur->_private) {
876
- nokogiri_root_node(cur);
1254
+ noko_xml_document_pin_node(cur);
877
1255
  xmlUnlinkNode(cur);
878
1256
  }
879
1257
  }
@@ -891,7 +1269,8 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
891
1269
  *
892
1270
  * Get the value for +attribute+
893
1271
  */
894
- static VALUE get(VALUE self, VALUE rattribute)
1272
+ static VALUE
1273
+ get(VALUE self, VALUE rattribute)
895
1274
  {
896
1275
  xmlNodePtr node;
897
1276
  xmlChar *value = 0;
@@ -905,7 +1284,7 @@ static VALUE get(VALUE self, VALUE rattribute)
905
1284
  Data_Get_Struct(self, xmlNode, node);
906
1285
  attribute = xmlCharStrdup(StringValueCStr(rattribute));
907
1286
 
908
- colon = (xmlChar *)(uintptr_t)xmlStrchr(attribute, (const xmlChar)':');
1287
+ colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':'));
909
1288
  if (colon) {
910
1289
  /* split the attribute string into separate prefix and name by
911
1290
  * null-terminating the prefix at the colon */
@@ -917,7 +1296,7 @@ static VALUE get(VALUE self, VALUE rattribute)
917
1296
  if (ns) {
918
1297
  value = xmlGetNsProp(node, attr_name, ns->href);
919
1298
  } else {
920
- value = xmlGetProp(node, (xmlChar*)StringValueCStr(rattribute));
1299
+ value = xmlGetProp(node, (xmlChar *)StringValueCStr(rattribute));
921
1300
  }
922
1301
  } else {
923
1302
  value = xmlGetNoNsProp(node, attribute);
@@ -938,14 +1317,15 @@ static VALUE get(VALUE self, VALUE rattribute)
938
1317
  *
939
1318
  * Set the namespace to +namespace+
940
1319
  */
941
- static VALUE set_namespace(VALUE self, VALUE namespace)
1320
+ static VALUE
1321
+ set_namespace(VALUE self, VALUE namespace)
942
1322
  {
943
1323
  xmlNodePtr node;
944
1324
  xmlNsPtr ns = NULL;
945
1325
 
946
1326
  Data_Get_Struct(self, xmlNode, node);
947
1327
 
948
- if(!NIL_P(namespace)) {
1328
+ if (!NIL_P(namespace)) {
949
1329
  Data_Get_Struct(namespace, xmlNs, ns);
950
1330
  }
951
1331
 
@@ -955,138 +1335,140 @@ static VALUE set_namespace(VALUE self, VALUE namespace)
955
1335
  }
956
1336
 
957
1337
  /*
958
- * call-seq:
959
- * attribute(name)
1338
+ * :call-seq:
1339
+ * namespace() → Namespace
960
1340
  *
961
- * Get the attribute node with +name+
962
- */
963
- static VALUE attr(VALUE self, VALUE name)
964
- {
965
- xmlNodePtr node;
966
- xmlAttrPtr prop;
967
- Data_Get_Struct(self, xmlNode, node);
968
- prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
969
-
970
- if(! prop) { return Qnil; }
971
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
972
- }
973
-
974
- /*
975
- * call-seq:
976
- * attribute_with_ns(name, namespace)
1341
+ * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
977
1342
  *
978
- * Get the attribute node with +name+ and +namespace+
979
- */
980
- static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
981
- {
982
- xmlNodePtr node;
983
- xmlAttrPtr prop;
984
- Data_Get_Struct(self, xmlNode, node);
985
- prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
986
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
987
-
988
- if(! prop) { return Qnil; }
989
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
990
- }
991
-
992
- /*
993
- * call-seq:
994
- * attribute_nodes()
1343
+ * *Example:*
995
1344
  *
996
- * returns a list containing the Node attributes.
1345
+ * doc = Nokogiri::XML(<<~EOF)
1346
+ * <root>
1347
+ * <first/>
1348
+ * <second xmlns="http://example.com/child"/>
1349
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1350
+ * </root>
1351
+ * EOF
1352
+ * doc.at_xpath("//first").namespace
1353
+ * # => nil
1354
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
1355
+ * # => #(Namespace:0x3c { href = "http://example.com/child" })
1356
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
1357
+ * # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
997
1358
  */
998
- static VALUE attribute_nodes(VALUE self)
1359
+ static VALUE
1360
+ rb_xml_node_namespace(VALUE rb_node)
999
1361
  {
1000
- /* this code in the mode of xmlHasProp() */
1001
- xmlNodePtr node;
1002
- VALUE attr;
1003
-
1004
- Data_Get_Struct(self, xmlNode, node);
1362
+ xmlNodePtr c_node ;
1363
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1005
1364
 
1006
- attr = rb_ary_new();
1007
- Nokogiri_xml_node_properties(node, attr);
1365
+ if (c_node->ns) {
1366
+ return noko_xml_namespace_wrap(c_node->ns, c_node->doc);
1367
+ }
1008
1368
 
1009
- return attr ;
1369
+ return Qnil ;
1010
1370
  }
1011
1371
 
1012
-
1013
1372
  /*
1014
- * call-seq:
1015
- * namespace()
1373
+ * :call-seq:
1374
+ * namespace_definitions() → Array<Nokogiri::XML::Namespace>
1016
1375
  *
1017
- * returns the namespace of the element or attribute node as a Namespace
1018
- * object, or nil if there is no namespace for the element or attribute.
1019
- */
1020
- static VALUE namespace(VALUE self)
1021
- {
1022
- xmlNodePtr node ;
1023
- Data_Get_Struct(self, xmlNode, node);
1024
-
1025
- if (node->ns) {
1026
- return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
1027
- }
1028
-
1029
- return Qnil ;
1030
- }
1031
-
1032
- /*
1033
- * call-seq:
1034
- * namespace_definitions()
1376
+ * [Returns]
1377
+ * Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
1378
+ * will be empty if no namespaces are defined on this node.
1379
+ *
1380
+ * *Example:*
1035
1381
  *
1036
- * returns namespaces defined on self element directly, as an array of Namespace objects. Includes both a default namespace (as in"xmlns="), and prefixed namespaces (as in "xmlns:prefix=").
1382
+ * doc = Nokogiri::XML(<<~EOF)
1383
+ * <root xmlns="http://example.com/root">
1384
+ * <first/>
1385
+ * <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
1386
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1387
+ * </root>
1388
+ * EOF
1389
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
1390
+ * # => []
1391
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
1392
+ * # => [#(Namespace:0x3c { href = "http://example.com/child" }),
1393
+ * # #(Namespace:0x50 {
1394
+ * # prefix = "unused",
1395
+ * # href = "http://example.com/unused"
1396
+ * # })]
1397
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
1398
+ * # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
1037
1399
  */
1038
- static VALUE namespace_definitions(VALUE self)
1400
+ static VALUE
1401
+ namespace_definitions(VALUE rb_node)
1039
1402
  {
1040
1403
  /* this code in the mode of xmlHasProp() */
1041
- xmlNodePtr node ;
1042
- VALUE list;
1043
- xmlNsPtr ns;
1044
-
1045
- Data_Get_Struct(self, xmlNode, node);
1404
+ xmlNodePtr c_node ;
1405
+ xmlNsPtr c_namespace;
1406
+ VALUE definitions = rb_ary_new();
1046
1407
 
1047
- list = rb_ary_new();
1408
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1048
1409
 
1049
- ns = node->nsDef;
1050
-
1051
- if(!ns) { return list; }
1410
+ c_namespace = c_node->nsDef;
1411
+ if (!c_namespace) {
1412
+ return definitions;
1413
+ }
1052
1414
 
1053
- while(NULL != ns) {
1054
- rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
1055
- ns = ns->next;
1415
+ while (c_namespace != NULL) {
1416
+ rb_ary_push(definitions, noko_xml_namespace_wrap(c_namespace, c_node->doc));
1417
+ c_namespace = c_namespace->next;
1056
1418
  }
1057
1419
 
1058
- return list;
1420
+ return definitions;
1059
1421
  }
1060
1422
 
1061
1423
  /*
1062
- * call-seq:
1063
- * namespace_scopes()
1424
+ * :call-seq:
1425
+ * namespace_scopes() → Array<Nokogiri::XML::Namespace>
1426
+ *
1427
+ * [Returns] Array of all the Namespaces on this node and its ancestors.
1064
1428
  *
1065
- * returns namespaces in scope for self -- those defined on self element
1066
- * directly or any ancestor node -- as an array of Namespace objects. Default
1067
- * namespaces ("xmlns=" style) for self are included in this array; Default
1068
- * namespaces for ancestors, however, are not. See also #namespaces
1429
+ * See also #namespaces
1430
+ *
1431
+ * *Example:*
1432
+ *
1433
+ * doc = Nokogiri::XML(<<~EOF)
1434
+ * <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
1435
+ * <first/>
1436
+ * <second xmlns="http://example.com/child"/>
1437
+ * <third xmlns:foo="http://example.com/foo"/>
1438
+ * </root>
1439
+ * EOF
1440
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
1441
+ * # => [#(Namespace:0x3c { href = "http://example.com/root" }),
1442
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1443
+ * doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
1444
+ * # => [#(Namespace:0x64 { href = "http://example.com/child" }),
1445
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1446
+ * doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
1447
+ * # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
1448
+ * # #(Namespace:0x3c { href = "http://example.com/root" }),
1449
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1069
1450
  */
1070
- static VALUE namespace_scopes(VALUE self)
1451
+ static VALUE
1452
+ rb_xml_node_namespace_scopes(VALUE rb_node)
1071
1453
  {
1072
- xmlNodePtr node ;
1073
- VALUE list;
1074
- xmlNsPtr *ns_list;
1454
+ xmlNodePtr c_node ;
1455
+ xmlNsPtr *namespaces;
1456
+ VALUE scopes = rb_ary_new();
1075
1457
  int j;
1076
1458
 
1077
- Data_Get_Struct(self, xmlNode, node);
1459
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1078
1460
 
1079
- list = rb_ary_new();
1080
- ns_list = xmlGetNsList(node->doc, node);
1081
-
1082
- if(!ns_list) { return list; }
1461
+ namespaces = xmlGetNsList(c_node->doc, c_node);
1462
+ if (!namespaces) {
1463
+ return scopes;
1464
+ }
1083
1465
 
1084
- for (j = 0 ; ns_list[j] != NULL ; ++j) {
1085
- rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns_list[j]));
1466
+ for (j = 0 ; namespaces[j] != NULL ; ++j) {
1467
+ rb_ary_push(scopes, noko_xml_namespace_wrap(namespaces[j], c_node->doc));
1086
1468
  }
1087
1469
 
1088
- xmlFree(ns_list);
1089
- return list;
1470
+ xmlFree(namespaces);
1471
+ return scopes;
1090
1472
  }
1091
1473
 
1092
1474
  /*
@@ -1095,7 +1477,8 @@ static VALUE namespace_scopes(VALUE self)
1095
1477
  *
1096
1478
  * Get the type for this Node
1097
1479
  */
1098
- static VALUE node_type(VALUE self)
1480
+ static VALUE
1481
+ node_type(VALUE self)
1099
1482
  {
1100
1483
  xmlNodePtr node;
1101
1484
  Data_Get_Struct(self, xmlNode, node);
@@ -1108,7 +1491,8 @@ static VALUE node_type(VALUE self)
1108
1491
  *
1109
1492
  * Set the content for this Node
1110
1493
  */
1111
- static VALUE set_native_content(VALUE self, VALUE content)
1494
+ static VALUE
1495
+ set_native_content(VALUE self, VALUE content)
1112
1496
  {
1113
1497
  xmlNodePtr node, child, next ;
1114
1498
  Data_Get_Struct(self, xmlNode, node);
@@ -1117,7 +1501,7 @@ static VALUE set_native_content(VALUE self, VALUE content)
1117
1501
  while (NULL != child) {
1118
1502
  next = child->next ;
1119
1503
  xmlUnlinkNode(child) ;
1120
- nokogiri_root_node(child);
1504
+ noko_xml_document_pin_node(child);
1121
1505
  child = next ;
1122
1506
  }
1123
1507
 
@@ -1125,42 +1509,20 @@ static VALUE set_native_content(VALUE self, VALUE content)
1125
1509
  return content;
1126
1510
  }
1127
1511
 
1128
- /*
1129
- * call-seq:
1130
- * content
1131
- *
1132
- * Returns the plaintext content for this Node. Note that entities will always
1133
- * be expanded in the returned string.
1134
- */
1135
- static VALUE get_native_content(VALUE self)
1136
- {
1137
- xmlNodePtr node;
1138
- xmlChar * content;
1139
-
1140
- Data_Get_Struct(self, xmlNode, node);
1141
-
1142
- content = xmlNodeGetContent(node);
1143
- if(content) {
1144
- VALUE rval = NOKOGIRI_STR_NEW2(content);
1145
- xmlFree(content);
1146
- return rval;
1147
- }
1148
- return Qnil;
1149
- }
1150
-
1151
1512
  /*
1152
1513
  * call-seq:
1153
1514
  * lang=
1154
1515
  *
1155
1516
  * Set the language of a node, i.e. the values of the xml:lang attribute.
1156
1517
  */
1157
- static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
1518
+ static VALUE
1519
+ set_lang(VALUE self_rb, VALUE lang_rb)
1158
1520
  {
1159
1521
  xmlNodePtr self ;
1160
- xmlChar* lang ;
1522
+ xmlChar *lang ;
1161
1523
 
1162
1524
  Data_Get_Struct(self_rb, xmlNode, self);
1163
- lang = (xmlChar*)StringValueCStr(lang_rb);
1525
+ lang = (xmlChar *)StringValueCStr(lang_rb);
1164
1526
 
1165
1527
  xmlNodeSetLang(self, lang);
1166
1528
 
@@ -1174,10 +1536,11 @@ static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
1174
1536
  * Searches the language of a node, i.e. the values of the xml:lang attribute or
1175
1537
  * the one carried by the nearest ancestor.
1176
1538
  */
1177
- static VALUE get_lang(VALUE self_rb)
1539
+ static VALUE
1540
+ get_lang(VALUE self_rb)
1178
1541
  {
1179
1542
  xmlNodePtr self ;
1180
- xmlChar* lang ;
1543
+ xmlChar *lang ;
1181
1544
  VALUE lang_rb ;
1182
1545
 
1183
1546
  Data_Get_Struct(self_rb, xmlNode, self);
@@ -1193,7 +1556,8 @@ static VALUE get_lang(VALUE self_rb)
1193
1556
  }
1194
1557
 
1195
1558
  /* :nodoc: */
1196
- static VALUE add_child(VALUE self, VALUE new_child)
1559
+ static VALUE
1560
+ add_child(VALUE self, VALUE new_child)
1197
1561
  {
1198
1562
  return reparent_node_with(self, new_child, xmlAddChild);
1199
1563
  }
@@ -1204,15 +1568,16 @@ static VALUE add_child(VALUE self, VALUE new_child)
1204
1568
  *
1205
1569
  * Get the parent Node for this Node
1206
1570
  */
1207
- static VALUE get_parent(VALUE self)
1571
+ static VALUE
1572
+ get_parent(VALUE self)
1208
1573
  {
1209
1574
  xmlNodePtr node, parent;
1210
1575
  Data_Get_Struct(self, xmlNode, node);
1211
1576
 
1212
1577
  parent = node->parent;
1213
- if(!parent) { return Qnil; }
1578
+ if (!parent) { return Qnil; }
1214
1579
 
1215
- return Nokogiri_wrap_xml_node(Qnil, parent) ;
1580
+ return noko_xml_node_wrap(Qnil, parent) ;
1216
1581
  }
1217
1582
 
1218
1583
  /*
@@ -1221,11 +1586,12 @@ static VALUE get_parent(VALUE self)
1221
1586
  *
1222
1587
  * Set the name for this Node
1223
1588
  */
1224
- static VALUE set_name(VALUE self, VALUE new_name)
1589
+ static VALUE
1590
+ set_name(VALUE self, VALUE new_name)
1225
1591
  {
1226
1592
  xmlNodePtr node;
1227
1593
  Data_Get_Struct(self, xmlNode, node);
1228
- xmlNodeSetName(node, (xmlChar*)StringValueCStr(new_name));
1594
+ xmlNodeSetName(node, (xmlChar *)StringValueCStr(new_name));
1229
1595
  return new_name;
1230
1596
  }
1231
1597
 
@@ -1235,11 +1601,12 @@ static VALUE set_name(VALUE self, VALUE new_name)
1235
1601
  *
1236
1602
  * Returns the name for this Node
1237
1603
  */
1238
- static VALUE get_name(VALUE self)
1604
+ static VALUE
1605
+ get_name(VALUE self)
1239
1606
  {
1240
1607
  xmlNodePtr node;
1241
1608
  Data_Get_Struct(self, xmlNode, node);
1242
- if(node->name) {
1609
+ if (node->name) {
1243
1610
  return NOKOGIRI_STR_NEW2(node->name);
1244
1611
  }
1245
1612
  return Qnil;
@@ -1251,28 +1618,39 @@ static VALUE get_name(VALUE self)
1251
1618
  *
1252
1619
  * Returns the path associated with this Node
1253
1620
  */
1254
- static VALUE path(VALUE self)
1621
+ static VALUE
1622
+ rb_xml_node_path(VALUE rb_node)
1255
1623
  {
1256
- xmlNodePtr node;
1257
- xmlChar *path ;
1624
+ xmlNodePtr c_node;
1625
+ xmlChar *c_path ;
1258
1626
  VALUE rval;
1259
1627
 
1260
- Data_Get_Struct(self, xmlNode, node);
1628
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1629
+
1630
+ c_path = xmlGetNodePath(c_node);
1631
+ if (c_path == NULL) {
1632
+ // see https://github.com/sparklemotion/nokogiri/issues/2250
1633
+ // this behavior is clearly undesirable, but is what libxml <= 2.9.10 returned, and so we
1634
+ // do this for now to preserve the behavior across libxml2 versions.
1635
+ rval = NOKOGIRI_STR_NEW2("?");
1636
+ } else {
1637
+ rval = NOKOGIRI_STR_NEW2(c_path);
1638
+ xmlFree(c_path);
1639
+ }
1261
1640
 
1262
- path = xmlGetNodePath(node);
1263
- rval = NOKOGIRI_STR_NEW2(path);
1264
- xmlFree(path);
1265
1641
  return rval ;
1266
1642
  }
1267
1643
 
1268
1644
  /* :nodoc: */
1269
- static VALUE add_next_sibling(VALUE self, VALUE new_sibling)
1645
+ static VALUE
1646
+ add_next_sibling(VALUE self, VALUE new_sibling)
1270
1647
  {
1271
1648
  return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
1272
1649
  }
1273
1650
 
1274
1651
  /* :nodoc: */
1275
- static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
1652
+ static VALUE
1653
+ add_previous_sibling(VALUE self, VALUE new_sibling)
1276
1654
  {
1277
1655
  return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
1278
1656
  }
@@ -1283,7 +1661,8 @@ static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
1283
1661
  *
1284
1662
  * Write this Node to +io+ with +encoding+ and +options+
1285
1663
  */
1286
- static VALUE native_write_to(
1664
+ static VALUE
1665
+ native_write_to(
1287
1666
  VALUE self,
1288
1667
  VALUE io,
1289
1668
  VALUE encoding,
@@ -1292,7 +1671,7 @@ static VALUE native_write_to(
1292
1671
  )
1293
1672
  {
1294
1673
  xmlNodePtr node;
1295
- const char * before_indent;
1674
+ const char *before_indent;
1296
1675
  xmlSaveCtxtPtr savectx;
1297
1676
 
1298
1677
  Data_Get_Struct(self, xmlNode, node);
@@ -1304,8 +1683,8 @@ static VALUE native_write_to(
1304
1683
  xmlTreeIndentString = StringValueCStr(indent_string);
1305
1684
 
1306
1685
  savectx = xmlSaveToIO(
1307
- (xmlOutputWriteCallback)io_write_callback,
1308
- (xmlOutputCloseCallback)io_close_callback,
1686
+ (xmlOutputWriteCallback)noko_io_write,
1687
+ (xmlOutputCloseCallback)noko_io_close,
1309
1688
  (void *)io,
1310
1689
  RTEST(encoding) ? StringValueCStr(encoding) : NULL,
1311
1690
  (int)NUM2INT(options)
@@ -1319,92 +1698,102 @@ static VALUE native_write_to(
1319
1698
  }
1320
1699
 
1321
1700
  /*
1322
- * call-seq:
1323
- * line
1701
+ * :call-seq:
1702
+ * line() → Integer
1703
+ *
1704
+ * [Returns] The line number of this Node.
1705
+ *
1706
+ * ---
1707
+ *
1708
+ * <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
1709
+ *
1710
+ * Semantic differences:
1711
+ * - The CRuby method reflects the node's line number <i>in the parsed string</i>
1712
+ * - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
1713
+ * corrections have been applied
1324
1714
  *
1325
- * Returns the line for this Node
1715
+ * Performance differences:
1716
+ * - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
1717
+ * (constant time)
1718
+ * - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
1719
+ * time, where n is the number of nodes before/above the element in the DOM)
1720
+ *
1721
+ * If you'd like to help improve the JRuby implementation, please review these issues and reach out
1722
+ * to the maintainers:
1723
+ * - https://github.com/sparklemotion/nokogiri/issues/1223
1724
+ * - https://github.com/sparklemotion/nokogiri/pull/2177
1725
+ * - https://github.com/sparklemotion/nokogiri/issues/2380
1326
1726
  */
1327
- static VALUE line(VALUE self)
1727
+ static VALUE
1728
+ rb_xml_node_line(VALUE rb_node)
1328
1729
  {
1329
- xmlNodePtr node;
1330
- Data_Get_Struct(self, xmlNode, node);
1730
+ xmlNodePtr c_node;
1731
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1331
1732
 
1332
- return INT2NUM(xmlGetLineNo(node));
1733
+ return INT2NUM(xmlGetLineNo(c_node));
1333
1734
  }
1334
1735
 
1335
1736
  /*
1336
1737
  * call-seq:
1337
- * add_namespace_definition(prefix, href)
1338
- *
1339
- * Adds a namespace definition with +prefix+ using +href+ value. The result is
1340
- * as if parsed XML for this node had included an attribute
1341
- * 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
1342
- * added by passing 'nil' for prefix. Namespaces added this way will not
1343
- * show up in #attributes, but they will be included as an xmlns attribute
1344
- * when the node is serialized to XML.
1738
+ * line=(num)
1739
+ *
1740
+ * Sets the line for this Node. num must be less than 65535.
1345
1741
  */
1346
- static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
1742
+ static VALUE
1743
+ rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
1347
1744
  {
1348
- xmlNodePtr node, namespace;
1349
- xmlNsPtr ns;
1350
-
1351
- Data_Get_Struct(self, xmlNode, node);
1352
- namespace = node ;
1745
+ xmlNodePtr c_node;
1746
+ int line_number = NUM2INT(rb_line_number);
1353
1747
 
1354
- ns = xmlSearchNs(
1355
- node->doc,
1356
- node,
1357
- (const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
1358
- );
1748
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1359
1749
 
1360
- if(!ns) {
1361
- if (node->type != XML_ELEMENT_NODE) {
1362
- namespace = node->parent;
1750
+ // libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
1751
+ // search for "psvi" in SAX2.c and tree.c to learn more.
1752
+ if (line_number < 65535) {
1753
+ c_node->line = (short) line_number;
1754
+ } else {
1755
+ c_node->line = 65535;
1756
+ if (c_node->type == XML_TEXT_NODE) {
1757
+ c_node->psvi = (void *)(ptrdiff_t) line_number;
1363
1758
  }
1364
- ns = xmlNewNs(
1365
- namespace,
1366
- (const xmlChar *)StringValueCStr(href),
1367
- (const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
1368
- );
1369
1759
  }
1370
1760
 
1371
- if (!ns) { return Qnil ; }
1372
-
1373
- if(NIL_P(prefix) || node != namespace) { xmlSetNs(node, ns); }
1374
-
1375
- return Nokogiri_wrap_xml_namespace(node->doc, ns);
1761
+ return rb_line_number;
1376
1762
  }
1377
1763
 
1378
- /*
1379
- * call-seq:
1380
- * new(name, document)
1381
- *
1382
- * Create a new node with +name+ sharing GC lifecycle with +document+
1383
- */
1384
- static VALUE new(int argc, VALUE *argv, VALUE klass)
1764
+ /* :nodoc: documented in lib/nokogiri/xml/node.rb */
1765
+ static VALUE
1766
+ rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
1385
1767
  {
1386
- xmlDocPtr doc;
1387
- xmlNodePtr node;
1388
- VALUE name;
1389
- VALUE document;
1768
+ xmlNodePtr c_document_node;
1769
+ xmlNodePtr c_node;
1770
+ VALUE rb_name;
1771
+ VALUE rb_document_node;
1390
1772
  VALUE rest;
1391
1773
  VALUE rb_node;
1392
1774
 
1393
- rb_scan_args(argc, argv, "2*", &name, &document, &rest);
1775
+ rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
1394
1776
 
1395
- Data_Get_Struct(document, xmlDoc, doc);
1777
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
1778
+ rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
1779
+ }
1780
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
1781
+ // TODO: deprecate allowing Node
1782
+ rb_warn("Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in a future release of Nokogiri.");
1783
+ }
1784
+ Data_Get_Struct(rb_document_node, xmlNode, c_document_node);
1396
1785
 
1397
- node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(name));
1398
- node->doc = doc->doc;
1399
- nokogiri_root_node(node);
1786
+ c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
1787
+ c_node->doc = c_document_node->doc;
1788
+ noko_xml_document_pin_node(c_node);
1400
1789
 
1401
- rb_node = Nokogiri_wrap_xml_node(
1790
+ rb_node = noko_xml_node_wrap(
1402
1791
  klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1403
- node
1792
+ c_node
1404
1793
  );
1405
1794
  rb_obj_call_init(rb_node, argc, argv);
1406
1795
 
1407
- if(rb_block_given_p()) { rb_yield(rb_node); }
1796
+ if (rb_block_given_p()) { rb_yield(rb_node); }
1408
1797
 
1409
1798
  return rb_node;
1410
1799
  }
@@ -1415,7 +1804,8 @@ static VALUE new(int argc, VALUE *argv, VALUE klass)
1415
1804
  *
1416
1805
  * Returns the Node as html.
1417
1806
  */
1418
- static VALUE dump_html(VALUE self)
1807
+ static VALUE
1808
+ dump_html(VALUE self)
1419
1809
  {
1420
1810
  xmlBufferPtr buf ;
1421
1811
  xmlNodePtr node ;
@@ -1436,7 +1826,8 @@ static VALUE dump_html(VALUE self)
1436
1826
  *
1437
1827
  * Compare this Node to +other+ with respect to their Document
1438
1828
  */
1439
- static VALUE compare(VALUE self, VALUE _other)
1829
+ static VALUE
1830
+ compare(VALUE self, VALUE _other)
1440
1831
  {
1441
1832
  xmlNodePtr node, other;
1442
1833
  Data_Get_Struct(self, xmlNode, node);
@@ -1453,7 +1844,8 @@ static VALUE compare(VALUE self, VALUE _other)
1453
1844
  * Loads and substitutes all xinclude elements below the node. The
1454
1845
  * parser context will be initialized with +options+.
1455
1846
  */
1456
- static VALUE process_xincludes(VALUE self, VALUE options)
1847
+ static VALUE
1848
+ process_xincludes(VALUE self, VALUE options)
1457
1849
  {
1458
1850
  int rcode ;
1459
1851
  xmlNodePtr node;
@@ -1469,7 +1861,7 @@ static VALUE process_xincludes(VALUE self, VALUE options)
1469
1861
  xmlErrorPtr error;
1470
1862
 
1471
1863
  error = xmlGetLastError();
1472
- if(error) {
1864
+ if (error) {
1473
1865
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
1474
1866
  } else {
1475
1867
  rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
@@ -1481,7 +1873,8 @@ static VALUE process_xincludes(VALUE self, VALUE options)
1481
1873
 
1482
1874
 
1483
1875
  /* TODO: DOCUMENT ME */
1484
- static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1876
+ static VALUE
1877
+ in_context(VALUE self, VALUE _str, VALUE _options)
1485
1878
  {
1486
1879
  xmlNodePtr node, list = 0, tmp, child_iter, node_children, doc_children;
1487
1880
  xmlNodeSetPtr set;
@@ -1530,9 +1923,7 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1530
1923
  */
1531
1924
  child_iter = node->doc->children ;
1532
1925
  while (child_iter) {
1533
- if (child_iter->parent != (xmlNodePtr)node->doc) {
1534
- child_iter->parent = (xmlNodePtr)node->doc;
1535
- }
1926
+ child_iter->parent = (xmlNodePtr)node->doc;
1536
1927
  child_iter = child_iter->next;
1537
1928
  }
1538
1929
 
@@ -1562,12 +1953,12 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1562
1953
 
1563
1954
  /* FIXME: This probably needs to handle more constants... */
1564
1955
  switch (error) {
1565
- case XML_ERR_INTERNAL_ERROR:
1566
- case XML_ERR_NO_MEMORY:
1567
- rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
1568
- break;
1569
- default:
1570
- break;
1956
+ case XML_ERR_INTERNAL_ERROR:
1957
+ case XML_ERR_NO_MEMORY:
1958
+ rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
1959
+ break;
1960
+ default:
1961
+ break;
1571
1962
  }
1572
1963
 
1573
1964
  set = xmlXPathNodeSetCreate(NULL);
@@ -1576,178 +1967,178 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1576
1967
  tmp = list->next;
1577
1968
  list->next = NULL;
1578
1969
  xmlXPathNodeSetAddUnique(set, list);
1579
- nokogiri_root_node(list);
1970
+ noko_xml_document_pin_node(list);
1580
1971
  list = tmp;
1581
1972
  }
1582
1973
 
1583
- return Nokogiri_wrap_xml_node_set(set, doc);
1974
+ return noko_xml_node_set_wrap(set, doc);
1584
1975
  }
1585
1976
 
1586
1977
 
1587
- VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
1978
+ VALUE
1979
+ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1588
1980
  {
1589
- VALUE document = Qnil ;
1590
- VALUE node_cache = Qnil ;
1591
- VALUE rb_node = Qnil ;
1981
+ VALUE rb_document, rb_node_cache, rb_node;
1592
1982
  nokogiriTuplePtr node_has_a_document;
1593
- xmlDocPtr doc;
1594
- void (*mark_method)(xmlNodePtr) = NULL ;
1983
+ xmlDocPtr c_doc;
1984
+ void (*f_mark)(xmlNodePtr) = NULL ;
1595
1985
 
1596
- assert(node);
1986
+ assert(c_node);
1597
1987
 
1598
- if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE) {
1599
- return DOC_RUBY_OBJECT(node->doc);
1988
+ if (c_node->type == XML_DOCUMENT_NODE || c_node->type == XML_HTML_DOCUMENT_NODE) {
1989
+ return DOC_RUBY_OBJECT(c_node->doc);
1600
1990
  }
1601
1991
 
1602
1992
  /* It's OK if the node doesn't have a fully-realized document (as in XML::Reader). */
1603
1993
  /* see https://github.com/sparklemotion/nokogiri/issues/95 */
1604
1994
  /* and https://github.com/sparklemotion/nokogiri/issues/439 */
1605
- doc = node->doc;
1606
- if (doc->type == XML_DOCUMENT_FRAG_NODE) { doc = doc->doc; }
1607
- node_has_a_document = DOC_RUBY_OBJECT_TEST(doc);
1995
+ c_doc = c_node->doc;
1996
+ if (c_doc->type == XML_DOCUMENT_FRAG_NODE) { c_doc = c_doc->doc; }
1997
+ node_has_a_document = DOC_RUBY_OBJECT_TEST(c_doc);
1608
1998
 
1609
- if(node->_private && node_has_a_document) {
1610
- return (VALUE)node->_private;
1999
+ if (c_node->_private && node_has_a_document) {
2000
+ return (VALUE)c_node->_private;
1611
2001
  }
1612
2002
 
1613
- if(!RTEST(klass)) {
1614
- switch(node->type) {
1615
- case XML_ELEMENT_NODE:
1616
- klass = cNokogiriXmlElement;
1617
- break;
1618
- case XML_TEXT_NODE:
1619
- klass = cNokogiriXmlText;
1620
- break;
1621
- case XML_ATTRIBUTE_NODE:
1622
- klass = cNokogiriXmlAttr;
1623
- break;
1624
- case XML_ENTITY_REF_NODE:
1625
- klass = cNokogiriXmlEntityReference;
1626
- break;
1627
- case XML_COMMENT_NODE:
1628
- klass = cNokogiriXmlComment;
1629
- break;
1630
- case XML_DOCUMENT_FRAG_NODE:
1631
- klass = cNokogiriXmlDocumentFragment;
1632
- break;
1633
- case XML_PI_NODE:
1634
- klass = cNokogiriXmlProcessingInstruction;
1635
- break;
1636
- case XML_ENTITY_DECL:
1637
- klass = cNokogiriXmlEntityDecl;
1638
- break;
1639
- case XML_CDATA_SECTION_NODE:
1640
- klass = cNokogiriXmlCData;
1641
- break;
1642
- case XML_DTD_NODE:
1643
- klass = cNokogiriXmlDtd;
1644
- break;
1645
- case XML_ATTRIBUTE_DECL:
1646
- klass = cNokogiriXmlAttributeDecl;
1647
- break;
1648
- case XML_ELEMENT_DECL:
1649
- klass = cNokogiriXmlElementDecl;
1650
- break;
1651
- default:
1652
- klass = cNokogiriXmlNode;
2003
+ if (!RTEST(rb_class)) {
2004
+ switch (c_node->type) {
2005
+ case XML_ELEMENT_NODE:
2006
+ rb_class = cNokogiriXmlElement;
2007
+ break;
2008
+ case XML_TEXT_NODE:
2009
+ rb_class = cNokogiriXmlText;
2010
+ break;
2011
+ case XML_ATTRIBUTE_NODE:
2012
+ rb_class = cNokogiriXmlAttr;
2013
+ break;
2014
+ case XML_ENTITY_REF_NODE:
2015
+ rb_class = cNokogiriXmlEntityReference;
2016
+ break;
2017
+ case XML_COMMENT_NODE:
2018
+ rb_class = cNokogiriXmlComment;
2019
+ break;
2020
+ case XML_DOCUMENT_FRAG_NODE:
2021
+ rb_class = cNokogiriXmlDocumentFragment;
2022
+ break;
2023
+ case XML_PI_NODE:
2024
+ rb_class = cNokogiriXmlProcessingInstruction;
2025
+ break;
2026
+ case XML_ENTITY_DECL:
2027
+ rb_class = cNokogiriXmlEntityDecl;
2028
+ break;
2029
+ case XML_CDATA_SECTION_NODE:
2030
+ rb_class = cNokogiriXmlCData;
2031
+ break;
2032
+ case XML_DTD_NODE:
2033
+ rb_class = cNokogiriXmlDtd;
2034
+ break;
2035
+ case XML_ATTRIBUTE_DECL:
2036
+ rb_class = cNokogiriXmlAttributeDecl;
2037
+ break;
2038
+ case XML_ELEMENT_DECL:
2039
+ rb_class = cNokogiriXmlElementDecl;
2040
+ break;
2041
+ default:
2042
+ rb_class = cNokogiriXmlNode;
1653
2043
  }
1654
2044
  }
1655
2045
 
1656
- mark_method = node_has_a_document ? mark : NULL ;
2046
+ f_mark = node_has_a_document ? _xml_node_mark : NULL ;
1657
2047
 
1658
- rb_node = Data_Wrap_Struct(klass, mark_method, debug_node_dealloc, node) ;
1659
- node->_private = (void *)rb_node;
2048
+ rb_node = Data_Wrap_Struct(rb_class, f_mark, _xml_node_dealloc, c_node) ;
2049
+ c_node->_private = (void *)rb_node;
1660
2050
 
1661
2051
  if (node_has_a_document) {
1662
- document = DOC_RUBY_OBJECT(doc);
1663
- node_cache = DOC_NODE_CACHE(doc);
1664
- rb_ary_push(node_cache, rb_node);
1665
- rb_funcall(document, decorate, 1, rb_node);
2052
+ rb_document = DOC_RUBY_OBJECT(c_doc);
2053
+ rb_node_cache = DOC_NODE_CACHE(c_doc);
2054
+ rb_ary_push(rb_node_cache, rb_node);
2055
+ rb_funcall(rb_document, id_decorate, 1, rb_node);
1666
2056
  }
1667
2057
 
1668
2058
  return rb_node ;
1669
2059
  }
1670
2060
 
1671
2061
 
1672
- void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
2062
+ /*
2063
+ * return Array<Nokogiri::XML::Attr> containing the node's attributes
2064
+ */
2065
+ VALUE
2066
+ noko_xml_node_attrs(xmlNodePtr c_node)
1673
2067
  {
1674
- xmlAttrPtr prop;
1675
- prop = node->properties ;
1676
- while (prop != NULL) {
1677
- rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
1678
- prop = prop->next ;
2068
+ VALUE rb_properties = rb_ary_new();
2069
+ xmlAttrPtr c_property;
2070
+
2071
+ c_property = c_node->properties ;
2072
+ while (c_property != NULL) {
2073
+ rb_ary_push(rb_properties, noko_xml_node_wrap(Qnil, (xmlNodePtr)c_property));
2074
+ c_property = c_property->next ;
1679
2075
  }
1680
- }
1681
2076
 
1682
- VALUE cNokogiriXmlNode ;
1683
- VALUE cNokogiriXmlElement ;
2077
+ return rb_properties;
2078
+ }
1684
2079
 
1685
- void init_xml_node()
2080
+ void
2081
+ noko_init_xml_node()
1686
2082
  {
1687
- VALUE nokogiri = rb_define_module("Nokogiri");
1688
- VALUE xml = rb_define_module_under(nokogiri, "XML");
1689
- VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
1690
-
1691
- cNokogiriXmlNode = klass;
1692
-
1693
- cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
1694
-
1695
- rb_define_singleton_method(klass, "new", new, -1);
1696
-
1697
- rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
1698
- rb_define_method(klass, "node_name", get_name, 0);
1699
- rb_define_method(klass, "document", document, 0);
1700
- rb_define_method(klass, "node_name=", set_name, 1);
1701
- rb_define_method(klass, "parent", get_parent, 0);
1702
- rb_define_method(klass, "child", child, 0);
1703
- rb_define_method(klass, "first_element_child", first_element_child, 0);
1704
- rb_define_method(klass, "last_element_child", last_element_child, 0);
1705
- rb_define_method(klass, "children", children, 0);
1706
- rb_define_method(klass, "element_children", element_children, 0);
1707
- rb_define_method(klass, "next_sibling", next_sibling, 0);
1708
- rb_define_method(klass, "previous_sibling", previous_sibling, 0);
1709
- rb_define_method(klass, "next_element", next_element, 0);
1710
- rb_define_method(klass, "previous_element", previous_element, 0);
1711
- rb_define_method(klass, "node_type", node_type, 0);
1712
- rb_define_method(klass, "path", path, 0);
1713
- rb_define_method(klass, "key?", key_eh, 1);
1714
- rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
1715
- rb_define_method(klass, "blank?", blank_eh, 0);
1716
- rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
1717
- rb_define_method(klass, "attribute", attr, 1);
1718
- rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
1719
- rb_define_method(klass, "namespace", namespace, 0);
1720
- rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
1721
- rb_define_method(klass, "namespace_scopes", namespace_scopes, 0);
1722
- rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
1723
- rb_define_method(klass, "dup", duplicate_node, -1);
1724
- rb_define_method(klass, "unlink", unlink_node, 0);
1725
- rb_define_method(klass, "internal_subset", internal_subset, 0);
1726
- rb_define_method(klass, "external_subset", external_subset, 0);
1727
- rb_define_method(klass, "create_internal_subset", create_internal_subset, 3);
1728
- rb_define_method(klass, "create_external_subset", create_external_subset, 3);
1729
- rb_define_method(klass, "pointer_id", pointer_id, 0);
1730
- rb_define_method(klass, "line", line, 0);
1731
- rb_define_method(klass, "content", get_native_content, 0);
1732
- rb_define_method(klass, "native_content=", set_native_content, 1);
1733
- rb_define_method(klass, "lang", get_lang, 0);
1734
- rb_define_method(klass, "lang=", set_lang, 1);
1735
-
1736
- rb_define_private_method(klass, "process_xincludes", process_xincludes, 1);
1737
- rb_define_private_method(klass, "in_context", in_context, 2);
1738
- rb_define_private_method(klass, "add_child_node", add_child, 1);
1739
- rb_define_private_method(klass, "add_previous_sibling_node", add_previous_sibling, 1);
1740
- rb_define_private_method(klass, "add_next_sibling_node", add_next_sibling, 1);
1741
- rb_define_private_method(klass, "replace_node", replace, 1);
1742
- rb_define_private_method(klass, "dump_html", dump_html, 0);
1743
- rb_define_private_method(klass, "native_write_to", native_write_to, 4);
1744
- rb_define_private_method(klass, "get", get, 1);
1745
- rb_define_private_method(klass, "set", set, 2);
1746
- rb_define_private_method(klass, "set_namespace", set_namespace, 1);
1747
- rb_define_private_method(klass, "compare", compare, 1);
1748
-
1749
- decorate = rb_intern("decorate");
1750
- decorate_bang = rb_intern("decorate!");
2083
+ cNokogiriXmlNode = rb_define_class_under(mNokogiriXml, "Node", rb_cObject);
2084
+
2085
+ rb_undef_alloc_func(cNokogiriXmlNode);
2086
+
2087
+ rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
2088
+
2089
+ rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
2090
+ rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
2091
+ rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
2092
+ rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
2093
+ rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
2094
+ rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
2095
+ rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
2096
+ rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
2097
+ rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
2098
+ rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
2099
+ rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
2100
+ rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2101
+ rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
2102
+ rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
2103
+ rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
2104
+ rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
2105
+ rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
2106
+ rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
2107
+ rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
2108
+ rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
2109
+ rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
2110
+ rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
2111
+ rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
2112
+ rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
2113
+ rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
2114
+ rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
2115
+ rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
2116
+ rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
2117
+ rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
2118
+ rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
2119
+ rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
2120
+ rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
2121
+ rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
2122
+ rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
2123
+ rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
2124
+ rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
2125
+ rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
2126
+ rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
2127
+ rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
2128
+
2129
+ rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
2130
+ rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
2131
+ rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
2132
+ rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
2133
+ rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
2134
+ rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
2135
+ rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
2136
+ rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
2137
+ rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
2138
+ rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
2139
+ rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
2140
+ rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
2141
+
2142
+ id_decorate = rb_intern("decorate");
2143
+ id_decorate_bang = rb_intern("decorate!");
1751
2144
  }
1752
-
1753
- /* vim: set noet sw=4 sws=4 */