nokogiri 1.8.5 → 1.15.3

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +40 -18
  3. data/LICENSE-DEPENDENCIES.md +1636 -1024
  4. data/LICENSE.md +5 -28
  5. data/README.md +203 -90
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +33 -61
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +867 -417
  10. data/ext/nokogiri/gumbo.c +594 -0
  11. data/ext/nokogiri/html4_document.c +165 -0
  12. data/ext/nokogiri/html4_element_description.c +299 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser_context.c +108 -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 +251 -105
  18. data/ext/nokogiri/nokogiri.h +215 -90
  19. data/ext/nokogiri/test_global_handlers.c +40 -0
  20. data/ext/nokogiri/xml_attr.c +42 -37
  21. data/ext/nokogiri/xml_attribute_decl.c +22 -22
  22. data/ext/nokogiri/xml_cdata.c +40 -31
  23. data/ext/nokogiri/xml_comment.c +20 -27
  24. data/ext/nokogiri/xml_document.c +401 -237
  25. data/ext/nokogiri/xml_document_fragment.c +13 -17
  26. data/ext/nokogiri/xml_dtd.c +64 -58
  27. data/ext/nokogiri/xml_element_content.c +63 -55
  28. data/ext/nokogiri/xml_element_decl.c +31 -31
  29. data/ext/nokogiri/xml_encoding_handler.c +54 -21
  30. data/ext/nokogiri/xml_entity_decl.c +37 -35
  31. data/ext/nokogiri/xml_entity_reference.c +17 -19
  32. data/ext/nokogiri/xml_namespace.c +136 -62
  33. data/ext/nokogiri/xml_node.c +1387 -678
  34. data/ext/nokogiri/xml_node_set.c +246 -216
  35. data/ext/nokogiri/xml_processing_instruction.c +18 -20
  36. data/ext/nokogiri/xml_reader.c +347 -212
  37. data/ext/nokogiri/xml_relax_ng.c +86 -77
  38. data/ext/nokogiri/xml_sax_parser.c +149 -124
  39. data/ext/nokogiri/xml_sax_parser_context.c +145 -103
  40. data/ext/nokogiri/xml_sax_push_parser.c +64 -36
  41. data/ext/nokogiri/xml_schema.c +138 -81
  42. data/ext/nokogiri/xml_syntax_error.c +42 -21
  43. data/ext/nokogiri/xml_text.c +36 -26
  44. data/ext/nokogiri/xml_xpath_context.c +366 -178
  45. data/ext/nokogiri/xslt_stylesheet.c +335 -189
  46. data/gumbo-parser/CHANGES.md +63 -0
  47. data/gumbo-parser/Makefile +111 -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 +630 -0
  59. data/gumbo-parser/src/error.h +148 -0
  60. data/gumbo-parser/src/foreign_attrs.c +103 -0
  61. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  62. data/gumbo-parser/src/insertion_mode.h +33 -0
  63. data/gumbo-parser/src/macros.h +91 -0
  64. data/gumbo-parser/src/nokogiri_gumbo.h +944 -0
  65. data/gumbo-parser/src/parser.c +4891 -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 +223 -0
  76. data/gumbo-parser/src/tag_lookup.c +382 -0
  77. data/gumbo-parser/src/tag_lookup.gperf +170 -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 +66 -0
  88. data/gumbo-parser/src/util.h +34 -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 +107 -104
  98. data/lib/nokogiri/css/tokenizer.rex +3 -2
  99. data/lib/nokogiri/css/xpath_visitor.rb +224 -95
  100. data/lib/nokogiri/css.rb +56 -17
  101. data/lib/nokogiri/decorators/slop.rb +9 -7
  102. data/lib/nokogiri/encoding_handler.rb +57 -0
  103. data/lib/nokogiri/extension.rb +32 -0
  104. data/lib/nokogiri/gumbo.rb +15 -0
  105. data/lib/nokogiri/html.rb +38 -27
  106. data/lib/nokogiri/{html → html4}/builder.rb +4 -2
  107. data/lib/nokogiri/html4/document.rb +214 -0
  108. data/lib/nokogiri/html4/document_fragment.rb +54 -0
  109. data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
  110. data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
  111. data/lib/nokogiri/html4/encoding_reader.rb +121 -0
  112. data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
  113. data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
  114. data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
  115. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
  116. data/lib/nokogiri/html4.rb +47 -0
  117. data/lib/nokogiri/html5/document.rb +168 -0
  118. data/lib/nokogiri/html5/document_fragment.rb +90 -0
  119. data/lib/nokogiri/html5/node.rb +103 -0
  120. data/lib/nokogiri/html5.rb +392 -0
  121. data/lib/nokogiri/jruby/dependencies.rb +3 -0
  122. data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
  123. data/lib/nokogiri/syntax_error.rb +2 -0
  124. data/lib/nokogiri/version/constant.rb +6 -0
  125. data/lib/nokogiri/version/info.rb +223 -0
  126. data/lib/nokogiri/version.rb +3 -108
  127. data/lib/nokogiri/xml/attr.rb +55 -3
  128. data/lib/nokogiri/xml/attribute_decl.rb +6 -2
  129. data/lib/nokogiri/xml/builder.rb +98 -54
  130. data/lib/nokogiri/xml/cdata.rb +3 -1
  131. data/lib/nokogiri/xml/character_data.rb +2 -0
  132. data/lib/nokogiri/xml/document.rb +312 -126
  133. data/lib/nokogiri/xml/document_fragment.rb +104 -48
  134. data/lib/nokogiri/xml/dtd.rb +4 -2
  135. data/lib/nokogiri/xml/element_content.rb +12 -2
  136. data/lib/nokogiri/xml/element_decl.rb +6 -2
  137. data/lib/nokogiri/xml/entity_decl.rb +7 -3
  138. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  139. data/lib/nokogiri/xml/namespace.rb +45 -0
  140. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  141. data/lib/nokogiri/xml/node.rb +1093 -411
  142. data/lib/nokogiri/xml/node_set.rb +173 -67
  143. data/lib/nokogiri/xml/notation.rb +13 -0
  144. data/lib/nokogiri/xml/parse_options.rb +145 -52
  145. data/lib/nokogiri/xml/pp/character_data.rb +9 -6
  146. data/lib/nokogiri/xml/pp/node.rb +42 -30
  147. data/lib/nokogiri/xml/pp.rb +4 -2
  148. data/lib/nokogiri/xml/processing_instruction.rb +4 -1
  149. data/lib/nokogiri/xml/reader.rb +21 -28
  150. data/lib/nokogiri/xml/relax_ng.rb +8 -2
  151. data/lib/nokogiri/xml/sax/document.rb +45 -49
  152. data/lib/nokogiri/xml/sax/parser.rb +39 -36
  153. data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
  154. data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
  155. data/lib/nokogiri/xml/sax.rb +6 -4
  156. data/lib/nokogiri/xml/schema.rb +19 -9
  157. data/lib/nokogiri/xml/searchable.rb +120 -72
  158. data/lib/nokogiri/xml/syntax_error.rb +6 -4
  159. data/lib/nokogiri/xml/text.rb +2 -0
  160. data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
  161. data/lib/nokogiri/xml/xpath.rb +15 -4
  162. data/lib/nokogiri/xml/xpath_context.rb +3 -3
  163. data/lib/nokogiri/xml.rb +38 -37
  164. data/lib/nokogiri/xslt/stylesheet.rb +3 -1
  165. data/lib/nokogiri/xslt.rb +101 -22
  166. data/lib/nokogiri.rb +59 -75
  167. data/lib/xsd/xmlparser/nokogiri.rb +29 -25
  168. data/patches/libxml2/0001-Remove-script-macro-support.patch +40 -0
  169. data/patches/libxml2/0002-Update-entities-to-remove-handling-of-ssi.patch +44 -0
  170. data/patches/libxml2/0003-libxml2.la-is-in-top_builddir.patch +25 -0
  171. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  172. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  173. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  174. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  175. data/ports/archives/libxml2-2.11.4.tar.xz +0 -0
  176. data/ports/archives/libxslt-1.1.38.tar.xz +0 -0
  177. metadata +126 -399
  178. data/.autotest +0 -22
  179. data/.cross_rubies +0 -8
  180. data/.editorconfig +0 -17
  181. data/.gemtest +0 -0
  182. data/.travis.yml +0 -63
  183. data/CHANGELOG.md +0 -1368
  184. data/CONTRIBUTING.md +0 -42
  185. data/C_CODING_STYLE.rdoc +0 -33
  186. data/Gemfile-libxml-ruby +0 -3
  187. data/Manifest.txt +0 -370
  188. data/ROADMAP.md +0 -111
  189. data/Rakefile +0 -348
  190. data/SECURITY.md +0 -19
  191. data/STANDARD_RESPONSES.md +0 -47
  192. data/Y_U_NO_GEMSPEC.md +0 -155
  193. data/appveyor.yml +0 -29
  194. data/build_all +0 -44
  195. data/ext/nokogiri/html_document.c +0 -170
  196. data/ext/nokogiri/html_document.h +0 -10
  197. data/ext/nokogiri/html_element_description.c +0 -279
  198. data/ext/nokogiri/html_element_description.h +0 -10
  199. data/ext/nokogiri/html_entity_lookup.c +0 -32
  200. data/ext/nokogiri/html_entity_lookup.h +0 -8
  201. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  202. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  203. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  204. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  205. data/ext/nokogiri/xml_attr.h +0 -9
  206. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  207. data/ext/nokogiri/xml_cdata.h +0 -9
  208. data/ext/nokogiri/xml_comment.h +0 -9
  209. data/ext/nokogiri/xml_document.h +0 -23
  210. data/ext/nokogiri/xml_document_fragment.h +0 -10
  211. data/ext/nokogiri/xml_dtd.h +0 -10
  212. data/ext/nokogiri/xml_element_content.h +0 -10
  213. data/ext/nokogiri/xml_element_decl.h +0 -9
  214. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  215. data/ext/nokogiri/xml_entity_decl.h +0 -10
  216. data/ext/nokogiri/xml_entity_reference.h +0 -9
  217. data/ext/nokogiri/xml_io.c +0 -61
  218. data/ext/nokogiri/xml_io.h +0 -11
  219. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  220. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  221. data/ext/nokogiri/xml_namespace.h +0 -15
  222. data/ext/nokogiri/xml_node.h +0 -13
  223. data/ext/nokogiri/xml_node_set.h +0 -12
  224. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  225. data/ext/nokogiri/xml_reader.h +0 -10
  226. data/ext/nokogiri/xml_relax_ng.h +0 -9
  227. data/ext/nokogiri/xml_sax_parser.h +0 -39
  228. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  229. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  230. data/ext/nokogiri/xml_schema.h +0 -9
  231. data/ext/nokogiri/xml_syntax_error.h +0 -13
  232. data/ext/nokogiri/xml_text.h +0 -9
  233. data/ext/nokogiri/xml_xpath_context.h +0 -10
  234. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  235. data/lib/nokogiri/html/document.rb +0 -335
  236. data/lib/nokogiri/html/document_fragment.rb +0 -49
  237. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  238. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  239. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  240. data/patches/libxml2/0002-Fix-nullptr-deref-with-XPath-logic-ops.patch +0 -54
  241. data/patches/libxml2/0003-Fix-infinite-loop-in-LZMA-decompression.patch +0 -50
  242. data/patches/sort-patches-by-date +0 -25
  243. data/ports/archives/libxml2-2.9.8.tar.gz +0 -0
  244. data/ports/archives/libxslt-1.1.32.tar.gz +0 -0
  245. data/suppressions/README.txt +0 -1
  246. data/suppressions/nokogiri_ruby-2.supp +0 -10
  247. data/tasks/test.rb +0 -100
  248. data/test/css/test_nthiness.rb +0 -226
  249. data/test/css/test_parser.rb +0 -386
  250. data/test/css/test_tokenizer.rb +0 -215
  251. data/test/css/test_xpath_visitor.rb +0 -96
  252. data/test/decorators/test_slop.rb +0 -23
  253. data/test/files/2ch.html +0 -108
  254. data/test/files/GH_1042.html +0 -18
  255. data/test/files/address_book.rlx +0 -12
  256. data/test/files/address_book.xml +0 -10
  257. data/test/files/atom.xml +0 -344
  258. data/test/files/bar/bar.xsd +0 -4
  259. data/test/files/bogus.xml +0 -0
  260. data/test/files/dont_hurt_em_why.xml +0 -422
  261. data/test/files/encoding.html +0 -82
  262. data/test/files/encoding.xhtml +0 -84
  263. data/test/files/exslt.xml +0 -8
  264. data/test/files/exslt.xslt +0 -35
  265. data/test/files/foo/foo.xsd +0 -4
  266. data/test/files/metacharset.html +0 -10
  267. data/test/files/namespace_pressure_test.xml +0 -1684
  268. data/test/files/noencoding.html +0 -47
  269. data/test/files/po.xml +0 -32
  270. data/test/files/po.xsd +0 -66
  271. data/test/files/saml/saml20assertion_schema.xsd +0 -283
  272. data/test/files/saml/saml20protocol_schema.xsd +0 -302
  273. data/test/files/saml/xenc_schema.xsd +0 -146
  274. data/test/files/saml/xmldsig_schema.xsd +0 -318
  275. data/test/files/shift_jis.html +0 -10
  276. data/test/files/shift_jis.xml +0 -5
  277. data/test/files/shift_jis_no_charset.html +0 -9
  278. data/test/files/slow-xpath.xml +0 -25509
  279. data/test/files/snuggles.xml +0 -3
  280. data/test/files/staff.dtd +0 -10
  281. data/test/files/staff.xml +0 -59
  282. data/test/files/staff.xslt +0 -32
  283. data/test/files/test_document_url/bar.xml +0 -2
  284. data/test/files/test_document_url/document.dtd +0 -4
  285. data/test/files/test_document_url/document.xml +0 -6
  286. data/test/files/tlm.html +0 -851
  287. data/test/files/to_be_xincluded.xml +0 -2
  288. data/test/files/valid_bar.xml +0 -2
  289. data/test/files/xinclude.xml +0 -4
  290. data/test/helper.rb +0 -271
  291. data/test/html/sax/test_parser.rb +0 -168
  292. data/test/html/sax/test_parser_context.rb +0 -46
  293. data/test/html/sax/test_parser_text.rb +0 -163
  294. data/test/html/sax/test_push_parser.rb +0 -87
  295. data/test/html/test_attributes.rb +0 -85
  296. data/test/html/test_builder.rb +0 -164
  297. data/test/html/test_document.rb +0 -712
  298. data/test/html/test_document_encoding.rb +0 -143
  299. data/test/html/test_document_fragment.rb +0 -310
  300. data/test/html/test_element_description.rb +0 -105
  301. data/test/html/test_named_characters.rb +0 -14
  302. data/test/html/test_node.rb +0 -212
  303. data/test/html/test_node_encoding.rb +0 -91
  304. data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +0 -14
  305. data/test/namespaces/test_namespaces_aliased_default.rb +0 -24
  306. data/test/namespaces/test_namespaces_in_builder_doc.rb +0 -75
  307. data/test/namespaces/test_namespaces_in_cloned_doc.rb +0 -31
  308. data/test/namespaces/test_namespaces_in_created_doc.rb +0 -75
  309. data/test/namespaces/test_namespaces_in_parsed_doc.rb +0 -80
  310. data/test/namespaces/test_namespaces_preservation.rb +0 -31
  311. data/test/test_convert_xpath.rb +0 -135
  312. data/test/test_css_cache.rb +0 -47
  313. data/test/test_encoding_handler.rb +0 -48
  314. data/test/test_memory_leak.rb +0 -156
  315. data/test/test_nokogiri.rb +0 -138
  316. data/test/test_soap4r_sax.rb +0 -52
  317. data/test/test_xslt_transforms.rb +0 -314
  318. data/test/xml/node/test_save_options.rb +0 -28
  319. data/test/xml/node/test_subclass.rb +0 -44
  320. data/test/xml/sax/test_parser.rb +0 -402
  321. data/test/xml/sax/test_parser_context.rb +0 -115
  322. data/test/xml/sax/test_parser_text.rb +0 -202
  323. data/test/xml/sax/test_push_parser.rb +0 -265
  324. data/test/xml/test_attr.rb +0 -74
  325. data/test/xml/test_attribute_decl.rb +0 -86
  326. data/test/xml/test_builder.rb +0 -341
  327. data/test/xml/test_c14n.rb +0 -180
  328. data/test/xml/test_cdata.rb +0 -54
  329. data/test/xml/test_comment.rb +0 -40
  330. data/test/xml/test_document.rb +0 -982
  331. data/test/xml/test_document_encoding.rb +0 -31
  332. data/test/xml/test_document_fragment.rb +0 -298
  333. data/test/xml/test_dtd.rb +0 -187
  334. data/test/xml/test_dtd_encoding.rb +0 -31
  335. data/test/xml/test_element_content.rb +0 -56
  336. data/test/xml/test_element_decl.rb +0 -73
  337. data/test/xml/test_entity_decl.rb +0 -122
  338. data/test/xml/test_entity_reference.rb +0 -262
  339. data/test/xml/test_namespace.rb +0 -96
  340. data/test/xml/test_node.rb +0 -1325
  341. data/test/xml/test_node_attributes.rb +0 -115
  342. data/test/xml/test_node_encoding.rb +0 -75
  343. data/test/xml/test_node_inheritance.rb +0 -32
  344. data/test/xml/test_node_reparenting.rb +0 -592
  345. data/test/xml/test_node_set.rb +0 -809
  346. data/test/xml/test_parse_options.rb +0 -64
  347. data/test/xml/test_processing_instruction.rb +0 -30
  348. data/test/xml/test_reader.rb +0 -620
  349. data/test/xml/test_reader_encoding.rb +0 -134
  350. data/test/xml/test_relax_ng.rb +0 -60
  351. data/test/xml/test_schema.rb +0 -142
  352. data/test/xml/test_syntax_error.rb +0 -36
  353. data/test/xml/test_text.rb +0 -60
  354. data/test/xml/test_unparented_node.rb +0 -483
  355. data/test/xml/test_xinclude.rb +0 -83
  356. data/test/xml/test_xpath.rb +0 -470
  357. data/test/xslt/test_custom_functions.rb +0 -133
  358. data/test/xslt/test_exception_handling.rb +0 -37
@@ -1,48 +1,73 @@
1
- #include <xml_node.h>
1
+ #include <nokogiri.h>
2
2
 
3
- static ID decorate, decorate_bang;
3
+ #include <stdbool.h>
4
4
 
5
- #ifdef DEBUG
6
- static void debug_node_dealloc(xmlNodePtr x)
7
- {
8
- NOKOGIRI_DEBUG_START(x)
9
- NOKOGIRI_DEBUG_END(x)
10
- }
11
- #else
12
- # define debug_node_dealloc 0
13
- #endif
5
+ // :stopdoc:
6
+
7
+ VALUE cNokogiriXmlNode ;
8
+ static ID id_decorate, id_decorate_bang;
9
+
10
+ typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
14
11
 
15
- static void mark(xmlNodePtr node)
12
+ static void
13
+ _xml_node_mark(void *ptr)
16
14
  {
15
+ xmlNodePtr node = ptr;
16
+
17
+ if (!DOC_RUBY_OBJECT_TEST(node->doc)) {
18
+ return;
19
+ }
20
+
17
21
  xmlDocPtr doc = node->doc;
18
- if(doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
19
- if(DOC_RUBY_OBJECT_TEST(doc)) {
22
+ if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
23
+ if (DOC_RUBY_OBJECT_TEST(doc)) {
20
24
  rb_gc_mark(DOC_RUBY_OBJECT(doc));
21
25
  }
22
- } else if(node->doc->_private) {
26
+ } else if (node->doc->_private) {
23
27
  rb_gc_mark((VALUE)doc->_private);
24
28
  }
25
29
  }
26
30
 
27
- /* :nodoc: */
28
- typedef xmlNodePtr (*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
31
+ #ifdef HAVE_RB_GC_LOCATION
32
+ static void
33
+ _xml_node_update_references(void *ptr)
34
+ {
35
+ xmlNodePtr node = ptr;
29
36
 
30
- /* :nodoc: */
31
- static void relink_namespace(xmlNodePtr reparented)
37
+ if (node->_private) {
38
+ node->_private = (void *)rb_gc_location((VALUE)node->_private);
39
+ }
40
+ }
41
+ #else
42
+ # define _xml_node_update_references 0
43
+ #endif
44
+
45
+ static const rb_data_type_t nokogiri_node_type = {
46
+ .wrap_struct_name = "Nokogiri::XML::Node",
47
+ .function = {
48
+ .dmark = _xml_node_mark,
49
+ .dcompact = _xml_node_update_references,
50
+ },
51
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
52
+ };
53
+
54
+ static void
55
+ relink_namespace(xmlNodePtr reparented)
32
56
  {
33
57
  xmlNodePtr child;
34
- xmlNsPtr ns;
58
+ xmlAttrPtr attr;
35
59
 
36
60
  if (reparented->type != XML_ATTRIBUTE_NODE &&
37
61
  reparented->type != XML_ELEMENT_NODE) { return; }
38
62
 
39
63
  if (reparented->ns == NULL || reparented->ns->prefix == NULL) {
40
- xmlChar *name = 0, *prefix = 0;
64
+ xmlNsPtr ns = NULL;
65
+ xmlChar *name = NULL, *prefix = NULL;
41
66
 
42
67
  name = xmlSplitQName2(reparented->name, &prefix);
43
68
 
44
69
  if (reparented->type == XML_ATTRIBUTE_NODE) {
45
- if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) {
70
+ if (prefix == NULL || strcmp((char *)prefix, XMLNS_PREFIX) == 0) {
46
71
  xmlFree(name);
47
72
  xmlFree(prefix);
48
73
  return;
@@ -51,10 +76,6 @@ static void relink_namespace(xmlNodePtr reparented)
51
76
 
52
77
  ns = xmlSearchNs(reparented->doc, reparented, prefix);
53
78
 
54
- if (ns == NULL && reparented->parent) {
55
- ns = xmlSearchNs(reparented->doc, reparented->parent, prefix);
56
- }
57
-
58
79
  if (ns != NULL) {
59
80
  xmlNodeSetName(reparented, name);
60
81
  xmlSetNs(reparented, ns);
@@ -68,7 +89,9 @@ static void relink_namespace(xmlNodePtr reparented)
68
89
  if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
69
90
 
70
91
  /* Make sure that our reparented node has the correct namespaces */
71
- if (!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent) {
92
+ if (!reparented->ns &&
93
+ (reparented->doc != (xmlDocPtr)reparented->parent) &&
94
+ (rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
72
95
  xmlSetNs(reparented, reparented->parent->ns);
73
96
  }
74
97
 
@@ -91,7 +114,7 @@ static void relink_namespace(xmlNodePtr reparented)
91
114
  } else {
92
115
  reparented->nsDef = curr->next;
93
116
  }
94
- nokogiri_root_nsdef(curr, reparented->doc);
117
+ noko_xml_document_pin_namespace(curr, reparented->doc);
95
118
  } else {
96
119
  prev = curr;
97
120
  }
@@ -99,6 +122,25 @@ static void relink_namespace(xmlNodePtr reparented)
99
122
  }
100
123
  }
101
124
 
125
+ /*
126
+ * Search our parents for an existing definition of current namespace,
127
+ * because the definition it's pointing to may have just been removed nsDef.
128
+ *
129
+ * And although that would technically probably be OK, I'd feel better if we
130
+ * referred to a namespace that's still present in a node's nsDef somewhere
131
+ * in the doc.
132
+ */
133
+ if (reparented->ns) {
134
+ xmlNsPtr ns = xmlSearchNs(reparented->doc, reparented, reparented->ns->prefix);
135
+ if (ns
136
+ && ns != reparented->ns
137
+ && xmlStrEqual(ns->prefix, reparented->ns->prefix)
138
+ && xmlStrEqual(ns->href, reparented->ns->href)
139
+ ) {
140
+ xmlSetNs(reparented, ns);
141
+ }
142
+ }
143
+
102
144
  /* Only walk all children if there actually is a namespace we need to */
103
145
  /* reparent. */
104
146
  if (NULL == reparented->ns) { return; }
@@ -112,16 +154,19 @@ static void relink_namespace(xmlNodePtr reparented)
112
154
  }
113
155
 
114
156
  if (reparented->type == XML_ELEMENT_NODE) {
115
- child = (xmlNodePtr)((xmlElementPtr)reparented)->attributes;
116
- while(NULL != child) {
117
- relink_namespace(child);
118
- child = child->next;
157
+ attr = reparented->properties;
158
+ while (NULL != attr) {
159
+ relink_namespace((xmlNodePtr)attr);
160
+ attr = attr->next;
119
161
  }
120
162
  }
121
163
  }
122
164
 
123
- /* :nodoc: */
124
- static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
165
+
166
+ /* internal function meant to wrap xmlReplaceNode
167
+ and fix some issues we have with libxml2 merging nodes */
168
+ static xmlNodePtr
169
+ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
125
170
  {
126
171
  xmlNodePtr retval ;
127
172
 
@@ -144,22 +189,34 @@ static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
144
189
  return retval ;
145
190
  }
146
191
 
147
- /* :nodoc: */
148
- static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
192
+
193
+ static void
194
+ raise_if_ancestor_of_self(xmlNodePtr self)
195
+ {
196
+ for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
197
+ if (self == ancestor) {
198
+ rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
199
+ }
200
+ }
201
+ }
202
+
203
+
204
+ static VALUE
205
+ reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
149
206
  {
150
207
  VALUE reparented_obj ;
151
- xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text, parent ;
208
+ xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ;
152
209
  int original_ns_prefix_is_default = 0 ;
153
210
 
154
- if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
211
+ if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
155
212
  rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
156
213
  }
157
- if(rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
214
+ if (rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
158
215
  rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
159
216
  }
160
217
 
161
- Data_Get_Struct(reparentee_obj, xmlNode, reparentee);
162
- Data_Get_Struct(pivot_obj, xmlNode, pivot);
218
+ Noko_Node_Get_Struct(reparentee_obj, xmlNode, reparentee);
219
+ Noko_Node_Get_Struct(pivot_obj, xmlNode, pivot);
163
220
 
164
221
  /*
165
222
  * Check if nodes given are appropriate to have a parent-child
@@ -175,66 +232,66 @@ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_rep
175
232
 
176
233
  if (parent) {
177
234
  switch (parent->type) {
178
- case XML_DOCUMENT_NODE:
179
- case XML_HTML_DOCUMENT_NODE:
180
- switch (reparentee->type) {
181
- case XML_ELEMENT_NODE:
182
- case XML_PI_NODE:
183
- case XML_COMMENT_NODE:
184
- case XML_DOCUMENT_TYPE_NODE:
185
- /*
186
- * The DOM specification says no to adding text-like nodes
187
- * directly to a document, but we allow it for compatibility.
188
- */
189
- case XML_TEXT_NODE:
190
- case XML_CDATA_SECTION_NODE:
191
- case XML_ENTITY_REF_NODE:
192
- goto ok;
193
- default:
235
+ case XML_DOCUMENT_NODE:
236
+ case XML_HTML_DOCUMENT_NODE:
237
+ switch (reparentee->type) {
238
+ case XML_ELEMENT_NODE:
239
+ case XML_PI_NODE:
240
+ case XML_COMMENT_NODE:
241
+ case XML_DOCUMENT_TYPE_NODE:
242
+ /*
243
+ * The DOM specification says no to adding text-like nodes
244
+ * directly to a document, but we allow it for compatibility.
245
+ */
246
+ case XML_TEXT_NODE:
247
+ case XML_CDATA_SECTION_NODE:
248
+ case XML_ENTITY_REF_NODE:
249
+ goto ok;
250
+ default:
251
+ break;
252
+ }
194
253
  break;
195
- }
196
- break;
197
- case XML_DOCUMENT_FRAG_NODE:
198
- case XML_ENTITY_REF_NODE:
199
- case XML_ELEMENT_NODE:
200
- switch (reparentee->type) {
201
- case XML_ELEMENT_NODE:
202
- case XML_PI_NODE:
203
- case XML_COMMENT_NODE:
204
- case XML_TEXT_NODE:
205
- case XML_CDATA_SECTION_NODE:
254
+ case XML_DOCUMENT_FRAG_NODE:
206
255
  case XML_ENTITY_REF_NODE:
207
- goto ok;
208
- default:
256
+ case XML_ELEMENT_NODE:
257
+ switch (reparentee->type) {
258
+ case XML_ELEMENT_NODE:
259
+ case XML_PI_NODE:
260
+ case XML_COMMENT_NODE:
261
+ case XML_TEXT_NODE:
262
+ case XML_CDATA_SECTION_NODE:
263
+ case XML_ENTITY_REF_NODE:
264
+ goto ok;
265
+ default:
266
+ break;
267
+ }
268
+ break;
269
+ case XML_ATTRIBUTE_NODE:
270
+ switch (reparentee->type) {
271
+ case XML_TEXT_NODE:
272
+ case XML_ENTITY_REF_NODE:
273
+ goto ok;
274
+ default:
275
+ break;
276
+ }
209
277
  break;
210
- }
211
- break;
212
- case XML_ATTRIBUTE_NODE:
213
- switch (reparentee->type) {
214
278
  case XML_TEXT_NODE:
215
- case XML_ENTITY_REF_NODE:
216
- goto ok;
279
+ /*
280
+ * xmlAddChild() breaks the DOM specification in that it allows
281
+ * adding a text node to another, in which case text nodes are
282
+ * coalesced, but since our JRuby version does not support such
283
+ * operation, we should inhibit it.
284
+ */
285
+ break;
217
286
  default:
218
287
  break;
219
- }
220
- break;
221
- case XML_TEXT_NODE:
222
- /*
223
- * xmlAddChild() breaks the DOM specification in that it allows
224
- * adding a text node to another, in which case text nodes are
225
- * coalesced, but since our JRuby version does not support such
226
- * operation, we should inhibit it.
227
- */
228
- break;
229
- default:
230
- break;
231
288
  }
232
289
 
233
290
  rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj));
234
291
  }
235
292
 
236
293
  ok:
237
- xmlUnlinkNode(reparentee);
294
+ original_reparentee = reparentee;
238
295
 
239
296
  if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
240
297
  /*
@@ -275,19 +332,25 @@ ok:
275
332
  original_ns_prefix_is_default = 1;
276
333
  }
277
334
 
278
- nokogiri_root_node(reparentee);
335
+ noko_xml_document_pin_node(reparentee);
279
336
 
280
337
  if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
281
338
  rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
282
339
  }
283
340
 
284
341
  if (original_ns_prefix_is_default && reparentee->ns != NULL && reparentee->ns->prefix != NULL) {
285
- /* issue #391, where new node's prefix may become the string "default" */
342
+ /*
343
+ * issue #391, where new node's prefix may become the string "default"
344
+ * see libxml2 tree.c xmlNewReconciliedNs which implements this behavior.
345
+ */
346
+ xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix));
286
347
  reparentee->ns->prefix = NULL;
287
348
  }
288
349
  }
289
350
 
290
- if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling
351
+ xmlUnlinkNode(original_reparentee);
352
+
353
+ if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling && prf != xmlAddChild
291
354
  && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
292
355
  /*
293
356
  * libxml merges text nodes in a right-to-left fashion, meaning that if
@@ -311,12 +374,12 @@ ok:
311
374
  new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
312
375
 
313
376
  xmlUnlinkNode(next_text);
314
- nokogiri_root_node(next_text);
377
+ noko_xml_document_pin_node(next_text);
315
378
 
316
379
  xmlAddNextSibling(pivot, new_next_text);
317
380
  }
318
381
 
319
- if(!(reparented = (*prf)(pivot, reparentee))) {
382
+ if (!(reparented = (*prf)(pivot, reparentee))) {
320
383
  rb_raise(rb_eRuntimeError, "Could not reparent node");
321
384
  }
322
385
 
@@ -326,57 +389,432 @@ ok:
326
389
  * adjacent text nodes.
327
390
  */
328
391
  DATA_PTR(reparentee_obj) = reparented ;
392
+ reparented_obj = noko_xml_node_wrap(Qnil, reparented);
329
393
 
330
- relink_namespace(reparented);
394
+ rb_funcall(reparented_obj, id_decorate_bang, 0);
331
395
 
332
- reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
396
+ /* if we've created a cycle, raise an exception */
397
+ raise_if_ancestor_of_self(reparented);
333
398
 
334
- rb_funcall(reparented_obj, decorate_bang, 0);
399
+ relink_namespace(reparented);
335
400
 
336
401
  return reparented_obj ;
337
402
  }
338
403
 
404
+ // :startdoc:
339
405
 
340
406
  /*
341
- * call-seq:
342
- * document
407
+ * :call-seq:
408
+ * add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
409
+ * add_namespace(prefix, href) → Nokogiri::XML::Namespace
410
+ *
411
+ * :category: Manipulating Document Structure
412
+ *
413
+ * Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
414
+ * included an attribute "xmlns:prefix=href".
415
+ *
416
+ * A default namespace definition for this node can be added by passing +nil+ for +prefix+.
417
+ *
418
+ * [Parameters]
419
+ * - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
420
+ * - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
421
+ *
422
+ * [Returns] The new Nokogiri::XML::Namespace
423
+ *
424
+ * *Example:* adding a non-default namespace definition
425
+ *
426
+ * doc = Nokogiri::XML("<store><inventory></inventory></store>")
427
+ * inventory = doc.at_css("inventory")
428
+ * inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
429
+ * inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
430
+ * inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
431
+ * doc.to_xml
432
+ * # => "<?xml version=\"1.0\"?>\n" +
433
+ * # "<store>\n" +
434
+ * # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
435
+ * # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
436
+ * # " </inventory>\n" +
437
+ * # "</store>\n"
438
+ *
439
+ * *Example:* adding a default namespace definition
440
+ *
441
+ * doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
442
+ * doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
443
+ * doc.to_xml
444
+ * # => "<?xml version=\"1.0\"?>\n" +
445
+ * # "<store>\n" +
446
+ * # " <inventory>\n" +
447
+ * # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
448
+ * # " </inventory>\n" +
449
+ * # "</store>\n"
450
+ *
451
+ */
452
+ static VALUE
453
+ rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
454
+ {
455
+ xmlNodePtr c_node, element;
456
+ xmlNsPtr c_namespace;
457
+ const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
458
+
459
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
460
+ element = c_node ;
461
+
462
+ c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
463
+
464
+ if (!c_namespace) {
465
+ if (c_node->type != XML_ELEMENT_NODE) {
466
+ element = c_node->parent;
467
+ }
468
+ c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
469
+ }
470
+
471
+ if (!c_namespace) {
472
+ return Qnil ;
473
+ }
474
+
475
+ if (NIL_P(rb_prefix) || c_node != element) {
476
+ xmlSetNs(c_node, c_namespace);
477
+ }
478
+
479
+ return noko_xml_namespace_wrap(c_namespace, c_node->doc);
480
+ }
481
+
482
+
483
+ /*
484
+ * :call-seq: attribute(name) → Nokogiri::XML::Attr
485
+ *
486
+ * :category: Working With Node Attributes
487
+ *
488
+ * [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
489
+ *
490
+ * ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
491
+ * used to find a matching attribute. In case of a simple name collision, only one of the matching
492
+ * attributes will be returned. In this case, you will need to use #attribute_with_ns.
493
+ *
494
+ * *Example:*
495
+ *
496
+ * doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
497
+ * child = doc.at_css("child")
498
+ * child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
499
+ * child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
500
+ *
501
+ * *Example* showing that namespaced attributes will not be returned:
502
+ *
503
+ * ⚠ Note that only one of the two matching attributes is returned.
504
+ *
505
+ * doc = Nokogiri::XML(<<~EOF)
506
+ * <root xmlns:width='http://example.com/widths'
507
+ * xmlns:height='http://example.com/heights'>
508
+ * <child width:size='broad' height:size='tall'/>
509
+ * </root>
510
+ * EOF
511
+ * doc.at_css("child").attribute("size")
512
+ * # => #(Attr:0x550 {
513
+ * # name = "size",
514
+ * # namespace = #(Namespace:0x564 {
515
+ * # prefix = "width",
516
+ * # href = "http://example.com/widths"
517
+ * # }),
518
+ * # value = "broad"
519
+ * # })
520
+ */
521
+ static VALUE
522
+ rb_xml_node_attribute(VALUE self, VALUE name)
523
+ {
524
+ xmlNodePtr node;
525
+ xmlAttrPtr prop;
526
+ Noko_Node_Get_Struct(self, xmlNode, node);
527
+ prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
528
+
529
+ if (! prop) { return Qnil; }
530
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
531
+ }
532
+
533
+
534
+ /*
535
+ * :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
536
+ *
537
+ * :category: Working With Node Attributes
538
+ *
539
+ * [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
540
+ *
541
+ * Note that this is the preferred alternative to #attributes when the simple
542
+ * (non-namespace-prefixed) attribute names may collide.
543
+ *
544
+ * *Example:*
545
+ *
546
+ * Contrast this with the colliding-name example from #attributes.
547
+ *
548
+ * doc = Nokogiri::XML(<<~EOF)
549
+ * <root xmlns:width='http://example.com/widths'
550
+ * xmlns:height='http://example.com/heights'>
551
+ * <child width:size='broad' height:size='tall'/>
552
+ * </root>
553
+ * EOF
554
+ * doc.at_css("child").attribute_nodes
555
+ * # => [#(Attr:0x550 {
556
+ * # name = "size",
557
+ * # namespace = #(Namespace:0x564 {
558
+ * # prefix = "width",
559
+ * # href = "http://example.com/widths"
560
+ * # }),
561
+ * # value = "broad"
562
+ * # }),
563
+ * # #(Attr:0x578 {
564
+ * # name = "size",
565
+ * # namespace = #(Namespace:0x58c {
566
+ * # prefix = "height",
567
+ * # href = "http://example.com/heights"
568
+ * # }),
569
+ * # value = "tall"
570
+ * # })]
571
+ */
572
+ static VALUE
573
+ rb_xml_node_attribute_nodes(VALUE rb_node)
574
+ {
575
+ xmlNodePtr c_node;
576
+
577
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
578
+
579
+ return noko_xml_node_attrs(c_node);
580
+ }
581
+
582
+
583
+ /*
584
+ * :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
585
+ *
586
+ * :category: Working With Node Attributes
587
+ *
588
+ * [Returns]
589
+ * Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
590
+ *
591
+ * [Parameters]
592
+ * - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
593
+ * - +namespace+ (String): the URI of the attribute's namespace
594
+ *
595
+ * See related: #attribute
596
+ *
597
+ * *Example:*
598
+ *
599
+ * doc = Nokogiri::XML(<<~EOF)
600
+ * <root xmlns:width='http://example.com/widths'
601
+ * xmlns:height='http://example.com/heights'>
602
+ * <child width:size='broad' height:size='tall'/>
603
+ * </root>
604
+ * EOF
605
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
606
+ * # => #(Attr:0x550 {
607
+ * # name = "size",
608
+ * # namespace = #(Namespace:0x564 {
609
+ * # prefix = "width",
610
+ * # href = "http://example.com/widths"
611
+ * # }),
612
+ * # value = "broad"
613
+ * # })
614
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
615
+ * # => #(Attr:0x578 {
616
+ * # name = "size",
617
+ * # namespace = #(Namespace:0x58c {
618
+ * # prefix = "height",
619
+ * # href = "http://example.com/heights"
620
+ * # }),
621
+ * # value = "tall"
622
+ * # })
623
+ */
624
+ static VALUE
625
+ rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
626
+ {
627
+ xmlNodePtr node;
628
+ xmlAttrPtr prop;
629
+ Noko_Node_Get_Struct(self, xmlNode, node);
630
+ prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
631
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
632
+
633
+ if (! prop) { return Qnil; }
634
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
635
+ }
636
+
637
+
638
+
639
+ /*
640
+ * call-seq: blank? → Boolean
641
+ *
642
+ * [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
643
+ *
644
+ * *Example:*
645
+ *
646
+ * Nokogiri("<root><child/></root>").root.child.blank? # => false
647
+ * Nokogiri("<root>\t \n</root>").root.child.blank? # => true
648
+ * Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
649
+ * Nokogiri("<root>not-blank</root>").root.child
650
+ * .tap { |n| n.content = "" }.blank # => true
651
+ */
652
+ static VALUE
653
+ rb_xml_node_blank_eh(VALUE self)
654
+ {
655
+ xmlNodePtr node;
656
+ Noko_Node_Get_Struct(self, xmlNode, node);
657
+ return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
658
+ }
659
+
660
+
661
+ /*
662
+ * :call-seq: child() → Nokogiri::XML::Node
663
+ *
664
+ * :category: Traversing Document Structure
665
+ *
666
+ * [Returns] First of this node's children, or +nil+ if there are no children
667
+ *
668
+ * This is a convenience method and is equivalent to:
669
+ *
670
+ * node.children.first
671
+ *
672
+ * See related: #children
673
+ */
674
+ static VALUE
675
+ rb_xml_node_child(VALUE self)
676
+ {
677
+ xmlNodePtr node, child;
678
+ Noko_Node_Get_Struct(self, xmlNode, node);
679
+
680
+ child = node->children;
681
+ if (!child) { return Qnil; }
682
+
683
+ return noko_xml_node_wrap(Qnil, child);
684
+ }
685
+
686
+
687
+ /*
688
+ * :call-seq: children() → Nokogiri::XML::NodeSet
689
+ *
690
+ * :category: Traversing Document Structure
691
+ *
692
+ * [Returns] Nokogiri::XML::NodeSet containing this node's children.
693
+ */
694
+ static VALUE
695
+ rb_xml_node_children(VALUE self)
696
+ {
697
+ xmlNodePtr node;
698
+ xmlNodePtr child;
699
+ xmlNodeSetPtr set;
700
+ VALUE document;
701
+ VALUE node_set;
702
+
703
+ Noko_Node_Get_Struct(self, xmlNode, node);
704
+
705
+ child = node->children;
706
+ set = xmlXPathNodeSetCreate(child);
707
+
708
+ document = DOC_RUBY_OBJECT(node->doc);
709
+
710
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
711
+
712
+ child = child->next;
713
+ while (NULL != child) {
714
+ xmlXPathNodeSetAddUnique(set, child);
715
+ child = child->next;
716
+ }
717
+
718
+ node_set = noko_xml_node_set_wrap(set, document);
719
+
720
+ return node_set;
721
+ }
722
+
723
+
724
+ /*
725
+ * :call-seq:
726
+ * content() → String
727
+ * inner_text() → String
728
+ * text() → String
729
+ * to_str() → String
730
+ *
731
+ * [Returns]
732
+ * Contents of all the text nodes in this node's subtree, concatenated together into a single
733
+ * String.
734
+ *
735
+ * ⚠ Note that entities will _always_ be expanded in the returned String.
736
+ *
737
+ * See related: #inner_html
738
+ *
739
+ * *Example* of how entities are handled:
740
+ *
741
+ * Note that <tt>&lt;</tt> becomes <tt><</tt> in the returned String.
343
742
  *
344
- * Get the document for this Node
743
+ * doc = Nokogiri::XML.fragment("<child>a &lt; b</child>")
744
+ * doc.at_css("child").content
745
+ * # => "a < b"
746
+ *
747
+ * *Example* of how a subtree is handled:
748
+ *
749
+ * Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
750
+ * concatenated into a single string.
751
+ *
752
+ * doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
753
+ * doc.at_css("child").content
754
+ * # => "first second"
345
755
  */
346
- static VALUE document(VALUE self)
756
+ static VALUE
757
+ rb_xml_node_content(VALUE self)
347
758
  {
348
759
  xmlNodePtr node;
349
- Data_Get_Struct(self, xmlNode, node);
760
+ xmlChar *content;
761
+
762
+ Noko_Node_Get_Struct(self, xmlNode, node);
763
+
764
+ content = xmlNodeGetContent(node);
765
+ if (content) {
766
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
767
+ xmlFree(content);
768
+ return rval;
769
+ }
770
+ return Qnil;
771
+ }
772
+
773
+
774
+ /*
775
+ * :call-seq: document() → Nokogiri::XML::Document
776
+ *
777
+ * :category: Traversing Document Structure
778
+ *
779
+ * [Returns] Parent Nokogiri::XML::Document for this node
780
+ */
781
+ static VALUE
782
+ rb_xml_node_document(VALUE self)
783
+ {
784
+ xmlNodePtr node;
785
+ Noko_Node_Get_Struct(self, xmlNode, node);
350
786
  return DOC_RUBY_OBJECT(node->doc);
351
787
  }
352
788
 
353
789
  /*
354
- * call-seq:
355
- * pointer_id
790
+ * :call-seq: pointer_id() → Integer
356
791
  *
357
- * Get the internal pointer number
792
+ * [Returns]
793
+ * A unique id for this node based on the internal memory structures. This method is used by #==
794
+ * to determine node identity.
358
795
  */
359
- static VALUE pointer_id(VALUE self)
796
+ static VALUE
797
+ rb_xml_node_pointer_id(VALUE self)
360
798
  {
361
799
  xmlNodePtr node;
362
- Data_Get_Struct(self, xmlNode, node);
800
+ Noko_Node_Get_Struct(self, xmlNode, node);
363
801
 
364
- return INT2NUM((long)(node));
802
+ return rb_uint2inum((uintptr_t)(node));
365
803
  }
366
804
 
367
805
  /*
368
- * call-seq:
369
- * encode_special_chars(string)
806
+ * :call-seq: encode_special_chars(string) → String
370
807
  *
371
808
  * Encode any special characters in +string+
372
809
  */
373
- static VALUE encode_special_chars(VALUE self, VALUE string)
810
+ static VALUE
811
+ encode_special_chars(VALUE self, VALUE string)
374
812
  {
375
813
  xmlNodePtr node;
376
814
  xmlChar *encoded;
377
815
  VALUE encoded_str;
378
816
 
379
- Data_Get_Struct(self, xmlNode, node);
817
+ Noko_Node_Get_Struct(self, xmlNode, node);
380
818
  encoded = xmlEncodeSpecialChars(
381
819
  node->doc,
382
820
  (const xmlChar *)StringValueCStr(string)
@@ -389,8 +827,8 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
389
827
  }
390
828
 
391
829
  /*
392
- * call-seq:
393
- * create_internal_subset(name, external_id, system_id)
830
+ * :call-seq:
831
+ * create_internal_subset(name, external_id, system_id)
394
832
  *
395
833
  * Create the internal subset of a document.
396
834
  *
@@ -400,17 +838,18 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
400
838
  * doc.create_internal_subset("chapter", nil, "chapter.dtd")
401
839
  * # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
402
840
  */
403
- static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
841
+ static VALUE
842
+ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
404
843
  {
405
844
  xmlNodePtr node;
406
845
  xmlDocPtr doc;
407
846
  xmlDtdPtr dtd;
408
847
 
409
- Data_Get_Struct(self, xmlNode, node);
848
+ Noko_Node_Get_Struct(self, xmlNode, node);
410
849
 
411
850
  doc = node->doc;
412
851
 
413
- if(xmlGetIntSubset(doc)) {
852
+ if (xmlGetIntSubset(doc)) {
414
853
  rb_raise(rb_eRuntimeError, "Document already has an internal subset");
415
854
  }
416
855
 
@@ -421,28 +860,29 @@ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, V
421
860
  NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
422
861
  );
423
862
 
424
- if(!dtd) { return Qnil; }
863
+ if (!dtd) { return Qnil; }
425
864
 
426
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
865
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
427
866
  }
428
867
 
429
868
  /*
430
- * call-seq:
431
- * create_external_subset(name, external_id, system_id)
869
+ * :call-seq:
870
+ * create_external_subset(name, external_id, system_id)
432
871
  *
433
872
  * Create an external subset
434
873
  */
435
- static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
874
+ static VALUE
875
+ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
436
876
  {
437
877
  xmlNodePtr node;
438
878
  xmlDocPtr doc;
439
879
  xmlDtdPtr dtd;
440
880
 
441
- Data_Get_Struct(self, xmlNode, node);
881
+ Noko_Node_Get_Struct(self, xmlNode, node);
442
882
 
443
883
  doc = node->doc;
444
884
 
445
- if(doc->extSubset) {
885
+ if (doc->extSubset) {
446
886
  rb_raise(rb_eRuntimeError, "Document already has an external subset");
447
887
  }
448
888
 
@@ -453,112 +893,124 @@ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, V
453
893
  NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
454
894
  );
455
895
 
456
- if(!dtd) { return Qnil; }
896
+ if (!dtd) { return Qnil; }
457
897
 
458
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
898
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
459
899
  }
460
900
 
461
901
  /*
462
- * call-seq:
463
- * external_subset
902
+ * :call-seq:
903
+ * external_subset()
464
904
  *
465
905
  * Get the external subset
466
906
  */
467
- static VALUE external_subset(VALUE self)
907
+ static VALUE
908
+ external_subset(VALUE self)
468
909
  {
469
910
  xmlNodePtr node;
470
911
  xmlDocPtr doc;
471
912
  xmlDtdPtr dtd;
472
913
 
473
- Data_Get_Struct(self, xmlNode, node);
914
+ Noko_Node_Get_Struct(self, xmlNode, node);
474
915
 
475
- if(!node->doc) { return Qnil; }
916
+ if (!node->doc) { return Qnil; }
476
917
 
477
918
  doc = node->doc;
478
919
  dtd = doc->extSubset;
479
920
 
480
- if(!dtd) { return Qnil; }
921
+ if (!dtd) { return Qnil; }
481
922
 
482
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
923
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
483
924
  }
484
925
 
485
926
  /*
486
- * call-seq:
487
- * internal_subset
927
+ * :call-seq:
928
+ * internal_subset()
488
929
  *
489
930
  * Get the internal subset
490
931
  */
491
- static VALUE internal_subset(VALUE self)
932
+ static VALUE
933
+ internal_subset(VALUE self)
492
934
  {
493
935
  xmlNodePtr node;
494
936
  xmlDocPtr doc;
495
937
  xmlDtdPtr dtd;
496
938
 
497
- Data_Get_Struct(self, xmlNode, node);
939
+ Noko_Node_Get_Struct(self, xmlNode, node);
498
940
 
499
- if(!node->doc) { return Qnil; }
941
+ if (!node->doc) { return Qnil; }
500
942
 
501
943
  doc = node->doc;
502
944
  dtd = xmlGetIntSubset(doc);
503
945
 
504
- if(!dtd) { return Qnil; }
946
+ if (!dtd) { return Qnil; }
505
947
 
506
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
948
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
507
949
  }
508
950
 
509
951
  /*
510
- * call-seq:
511
- * dup
952
+ * :call-seq:
953
+ * dup → Nokogiri::XML::Node
954
+ * dup(depth) → Nokogiri::XML::Node
955
+ * dup(depth, new_parent_doc) → Nokogiri::XML::Node
956
+ *
957
+ * Copy this node.
512
958
  *
513
- * Copy this node. An optional depth may be passed in, but it defaults
514
- * to a deep copy. 0 is a shallow copy, 1 is a deep copy.
959
+ * [Parameters]
960
+ * - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
961
+ * - +new_parent_doc+
962
+ * The new node's parent Document. Defaults to the this node's document.
963
+ *
964
+ * [Returns] The new Nokgiri::XML::Node
515
965
  */
516
- static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
966
+ static VALUE
967
+ duplicate_node(int argc, VALUE *argv, VALUE self)
517
968
  {
518
- VALUE level;
969
+ VALUE r_level, r_new_parent_doc;
970
+ int level;
971
+ int n_args;
972
+ xmlDocPtr new_parent_doc;
519
973
  xmlNodePtr node, dup;
520
974
 
521
- if(rb_scan_args(argc, argv, "01", &level) == 0) {
522
- level = INT2NUM((long)1);
975
+ Noko_Node_Get_Struct(self, xmlNode, node);
976
+
977
+ n_args = rb_scan_args(argc, argv, "02", &r_level, &r_new_parent_doc);
978
+
979
+ if (n_args < 1) {
980
+ r_level = INT2NUM((long)1);
523
981
  }
982
+ level = (int)NUM2INT(r_level);
524
983
 
525
- Data_Get_Struct(self, xmlNode, node);
984
+ if (n_args < 2) {
985
+ new_parent_doc = node->doc;
986
+ } else {
987
+ new_parent_doc = noko_xml_document_unwrap(r_new_parent_doc);
988
+ }
526
989
 
527
- dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
528
- if(dup == NULL) { return Qnil; }
990
+ dup = xmlDocCopyNode(node, new_parent_doc, level);
991
+ if (dup == NULL) { return Qnil; }
529
992
 
530
- nokogiri_root_node(dup);
993
+ noko_xml_document_pin_node(dup);
531
994
 
532
- return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
995
+ return noko_xml_node_wrap(rb_obj_class(self), dup);
533
996
  }
534
997
 
535
998
  /*
536
- * call-seq:
537
- * unlink
999
+ * :call-seq:
1000
+ * unlink() → self
538
1001
  *
539
1002
  * Unlink this node from its current context.
540
1003
  */
541
- static VALUE unlink_node(VALUE self)
1004
+ static VALUE
1005
+ unlink_node(VALUE self)
542
1006
  {
543
1007
  xmlNodePtr node;
544
- Data_Get_Struct(self, xmlNode, node);
1008
+ Noko_Node_Get_Struct(self, xmlNode, node);
545
1009
  xmlUnlinkNode(node);
546
- nokogiri_root_node(node);
1010
+ noko_xml_document_pin_node(node);
547
1011
  return self;
548
1012
  }
549
1013
 
550
- /*
551
- * call-seq:
552
- * blank?
553
- *
554
- * Is this node blank?
555
- */
556
- static VALUE blank_eh(VALUE self)
557
- {
558
- xmlNodePtr node;
559
- Data_Get_Struct(self, xmlNode, node);
560
- return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
561
- }
562
1014
 
563
1015
  /*
564
1016
  * call-seq:
@@ -566,15 +1018,16 @@ static VALUE blank_eh(VALUE self)
566
1018
  *
567
1019
  * Returns the next sibling node
568
1020
  */
569
- static VALUE next_sibling(VALUE self)
1021
+ static VALUE
1022
+ next_sibling(VALUE self)
570
1023
  {
571
1024
  xmlNodePtr node, sibling;
572
- Data_Get_Struct(self, xmlNode, node);
1025
+ Noko_Node_Get_Struct(self, xmlNode, node);
573
1026
 
574
1027
  sibling = node->next;
575
- if(!sibling) { return Qnil; }
1028
+ if (!sibling) { return Qnil; }
576
1029
 
577
- return Nokogiri_wrap_xml_node(Qnil, sibling) ;
1030
+ return noko_xml_node_wrap(Qnil, sibling) ;
578
1031
  }
579
1032
 
580
1033
  /*
@@ -583,15 +1036,16 @@ static VALUE next_sibling(VALUE self)
583
1036
  *
584
1037
  * Returns the previous sibling node
585
1038
  */
586
- static VALUE previous_sibling(VALUE self)
1039
+ static VALUE
1040
+ previous_sibling(VALUE self)
587
1041
  {
588
1042
  xmlNodePtr node, sibling;
589
- Data_Get_Struct(self, xmlNode, node);
1043
+ Noko_Node_Get_Struct(self, xmlNode, node);
590
1044
 
591
1045
  sibling = node->prev;
592
- if(!sibling) { return Qnil; }
1046
+ if (!sibling) { return Qnil; }
593
1047
 
594
- return Nokogiri_wrap_xml_node(Qnil, sibling);
1048
+ return noko_xml_node_wrap(Qnil, sibling);
595
1049
  }
596
1050
 
597
1051
  /*
@@ -600,15 +1054,16 @@ static VALUE previous_sibling(VALUE self)
600
1054
  *
601
1055
  * Returns the next Nokogiri::XML::Element type sibling node.
602
1056
  */
603
- static VALUE next_element(VALUE self)
1057
+ static VALUE
1058
+ next_element(VALUE self)
604
1059
  {
605
1060
  xmlNodePtr node, sibling;
606
- Data_Get_Struct(self, xmlNode, node);
1061
+ Noko_Node_Get_Struct(self, xmlNode, node);
607
1062
 
608
1063
  sibling = xmlNextElementSibling(node);
609
- if(!sibling) { return Qnil; }
1064
+ if (!sibling) { return Qnil; }
610
1065
 
611
- return Nokogiri_wrap_xml_node(Qnil, sibling);
1066
+ return noko_xml_node_wrap(Qnil, sibling);
612
1067
  }
613
1068
 
614
1069
  /*
@@ -617,82 +1072,60 @@ static VALUE next_element(VALUE self)
617
1072
  *
618
1073
  * Returns the previous Nokogiri::XML::Element type sibling node.
619
1074
  */
620
- static VALUE previous_element(VALUE self)
1075
+ static VALUE
1076
+ previous_element(VALUE self)
621
1077
  {
622
1078
  xmlNodePtr node, sibling;
623
- Data_Get_Struct(self, xmlNode, node);
1079
+ Noko_Node_Get_Struct(self, xmlNode, node);
624
1080
 
625
1081
  /*
626
1082
  * note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
627
1083
  */
628
1084
  sibling = node->prev;
629
- if(!sibling) { return Qnil; }
1085
+ if (!sibling) { return Qnil; }
630
1086
 
631
- while(sibling && sibling->type != XML_ELEMENT_NODE) {
1087
+ while (sibling && sibling->type != XML_ELEMENT_NODE) {
632
1088
  sibling = sibling->prev;
633
1089
  }
634
1090
 
635
- return sibling ? Nokogiri_wrap_xml_node(Qnil, sibling) : Qnil ;
1091
+ return sibling ? noko_xml_node_wrap(Qnil, sibling) : Qnil ;
636
1092
  }
637
1093
 
638
1094
  /* :nodoc: */
639
- static VALUE replace(VALUE self, VALUE new_node)
1095
+ static VALUE
1096
+ replace(VALUE self, VALUE new_node)
640
1097
  {
641
1098
  VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper);
642
1099
 
643
1100
  xmlNodePtr pivot;
644
- Data_Get_Struct(self, xmlNode, pivot);
645
- nokogiri_root_node(pivot);
1101
+ Noko_Node_Get_Struct(self, xmlNode, pivot);
1102
+ noko_xml_document_pin_node(pivot);
646
1103
 
647
1104
  return reparent;
648
1105
  }
649
1106
 
650
1107
  /*
651
- * call-seq:
652
- * children
1108
+ * :call-seq:
1109
+ * element_children() → NodeSet
1110
+ * elements() → NodeSet
653
1111
  *
654
- * Get the list of children for this node as a NodeSet
655
- */
656
- static VALUE children(VALUE self)
657
- {
658
- xmlNodePtr node;
659
- xmlNodePtr child;
660
- xmlNodeSetPtr set;
661
- VALUE document;
662
- VALUE node_set;
663
-
664
- Data_Get_Struct(self, xmlNode, node);
665
-
666
- child = node->children;
667
- set = xmlXPathNodeSetCreate(child);
668
-
669
- document = DOC_RUBY_OBJECT(node->doc);
670
-
671
- if(!child) { return Nokogiri_wrap_xml_node_set(set, document); }
672
-
673
- child = child->next;
674
- while(NULL != child) {
675
- xmlXPathNodeSetAddUnique(set, child);
676
- child = child->next;
677
- }
678
-
679
- node_set = Nokogiri_wrap_xml_node_set(set, document);
680
-
681
- return node_set;
682
- }
683
-
684
- /*
685
- * call-seq:
686
- * element_children
1112
+ * [Returns]
1113
+ * The node's child elements as a NodeSet. Only children that are elements will be returned, which
1114
+ * notably excludes Text nodes.
687
1115
  *
688
- * Get the list of children for this node as a NodeSet. All nodes will be
689
- * element nodes.
1116
+ * *Example:*
690
1117
  *
691
- * Example:
1118
+ * Note that #children returns the Text node "hello" while #element_children does not.
692
1119
  *
693
- * @doc.root.element_children.all? { |x| x.element? } # => true
1120
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1121
+ * div.element_children
1122
+ * # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
1123
+ * div.children
1124
+ * # => [#<Nokogiri::XML::Text:0x64 "hello">,
1125
+ * # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
694
1126
  */
695
- static VALUE element_children(VALUE self)
1127
+ static VALUE
1128
+ rb_xml_node_element_children(VALUE self)
696
1129
  {
697
1130
  xmlNodePtr node;
698
1131
  xmlNodePtr child;
@@ -700,83 +1133,78 @@ static VALUE element_children(VALUE self)
700
1133
  VALUE document;
701
1134
  VALUE node_set;
702
1135
 
703
- Data_Get_Struct(self, xmlNode, node);
1136
+ Noko_Node_Get_Struct(self, xmlNode, node);
704
1137
 
705
1138
  child = xmlFirstElementChild(node);
706
1139
  set = xmlXPathNodeSetCreate(child);
707
1140
 
708
1141
  document = DOC_RUBY_OBJECT(node->doc);
709
1142
 
710
- if(!child) { return Nokogiri_wrap_xml_node_set(set, document); }
711
-
712
- child = xmlNextElementSibling(child);
713
- while(NULL != child) {
714
- xmlXPathNodeSetAddUnique(set, child);
715
- child = xmlNextElementSibling(child);
716
- }
717
-
718
- node_set = Nokogiri_wrap_xml_node_set(set, document);
1143
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
719
1144
 
720
- return node_set;
721
- }
722
-
723
- /*
724
- * call-seq:
725
- * child
726
- *
727
- * Returns the child node
728
- */
729
- static VALUE child(VALUE self)
730
- {
731
- xmlNodePtr node, child;
732
- Data_Get_Struct(self, xmlNode, node);
1145
+ child = xmlNextElementSibling(child);
1146
+ while (NULL != child) {
1147
+ xmlXPathNodeSetAddUnique(set, child);
1148
+ child = xmlNextElementSibling(child);
1149
+ }
733
1150
 
734
- child = node->children;
735
- if(!child) { return Qnil; }
1151
+ node_set = noko_xml_node_set_wrap(set, document);
736
1152
 
737
- return Nokogiri_wrap_xml_node(Qnil, child);
1153
+ return node_set;
738
1154
  }
739
1155
 
740
1156
  /*
741
- * call-seq:
742
- * first_element_child
1157
+ * :call-seq:
1158
+ * first_element_child() → Node
743
1159
  *
744
- * Returns the first child node of this node that is an element.
1160
+ * [Returns] The first child Node that is an element.
745
1161
  *
746
- * Example:
1162
+ * *Example:*
747
1163
  *
748
- * @doc.root.first_element_child.element? # => true
1164
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
1165
+ * returned.
1166
+ *
1167
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1168
+ * div.first_element_child
1169
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
749
1170
  */
750
- static VALUE first_element_child(VALUE self)
1171
+ static VALUE
1172
+ rb_xml_node_first_element_child(VALUE self)
751
1173
  {
752
1174
  xmlNodePtr node, child;
753
- Data_Get_Struct(self, xmlNode, node);
1175
+ Noko_Node_Get_Struct(self, xmlNode, node);
754
1176
 
755
1177
  child = xmlFirstElementChild(node);
756
- if(!child) { return Qnil; }
1178
+ if (!child) { return Qnil; }
757
1179
 
758
- return Nokogiri_wrap_xml_node(Qnil, child);
1180
+ return noko_xml_node_wrap(Qnil, child);
759
1181
  }
760
1182
 
761
1183
  /*
762
- * call-seq:
763
- * last_element_child
1184
+ * :call-seq:
1185
+ * last_element_child() → Node
764
1186
  *
765
- * Returns the last child node of this node that is an element.
1187
+ * [Returns] The last child Node that is an element.
766
1188
  *
767
- * Example:
1189
+ * *Example:*
768
1190
  *
769
- * @doc.root.last_element_child.element? # => true
1191
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
1192
+ * element is returned.
1193
+ *
1194
+ * div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
1195
+ * div.last_element_child
1196
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
770
1197
  */
771
- static VALUE last_element_child(VALUE self)
1198
+ static VALUE
1199
+ rb_xml_node_last_element_child(VALUE self)
772
1200
  {
773
1201
  xmlNodePtr node, child;
774
- Data_Get_Struct(self, xmlNode, node);
1202
+ Noko_Node_Get_Struct(self, xmlNode, node);
775
1203
 
776
1204
  child = xmlLastElementChild(node);
777
- if(!child) { return Qnil; }
1205
+ if (!child) { return Qnil; }
778
1206
 
779
- return Nokogiri_wrap_xml_node(Qnil, child);
1207
+ return noko_xml_node_wrap(Qnil, child);
780
1208
  }
781
1209
 
782
1210
  /*
@@ -785,11 +1213,12 @@ static VALUE last_element_child(VALUE self)
785
1213
  *
786
1214
  * Returns true if +attribute+ is set
787
1215
  */
788
- static VALUE key_eh(VALUE self, VALUE attribute)
1216
+ static VALUE
1217
+ key_eh(VALUE self, VALUE attribute)
789
1218
  {
790
1219
  xmlNodePtr node;
791
- Data_Get_Struct(self, xmlNode, node);
792
- if(xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
1220
+ Noko_Node_Get_Struct(self, xmlNode, node);
1221
+ if (xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
793
1222
  return Qtrue;
794
1223
  }
795
1224
  return Qfalse;
@@ -801,12 +1230,13 @@ static VALUE key_eh(VALUE self, VALUE attribute)
801
1230
  *
802
1231
  * Returns true if +attribute+ is set with +namespace+
803
1232
  */
804
- static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
1233
+ static VALUE
1234
+ namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
805
1235
  {
806
1236
  xmlNodePtr node;
807
- Data_Get_Struct(self, xmlNode, node);
808
- if(xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
809
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
1237
+ Noko_Node_Get_Struct(self, xmlNode, node);
1238
+ if (xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
1239
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
810
1240
  return Qtrue;
811
1241
  }
812
1242
  return Qfalse;
@@ -818,11 +1248,12 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
818
1248
  *
819
1249
  * Set the +property+ to +value+
820
1250
  */
821
- static VALUE set(VALUE self, VALUE property, VALUE value)
1251
+ static VALUE
1252
+ set(VALUE self, VALUE property, VALUE value)
822
1253
  {
823
1254
  xmlNodePtr node, cur;
824
1255
  xmlAttrPtr prop;
825
- Data_Get_Struct(self, xmlNode, node);
1256
+ Noko_Node_Get_Struct(self, xmlNode, node);
826
1257
 
827
1258
  /* If a matching attribute node already exists, then xmlSetProp will destroy
828
1259
  * the existing node's children. However, if Nokogiri has a node object
@@ -831,13 +1262,13 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
831
1262
  * We can avoid this by unlinking these nodes first.
832
1263
  */
833
1264
  if (node->type != XML_ELEMENT_NODE) {
834
- return(Qnil);
1265
+ return (Qnil);
835
1266
  }
836
1267
  prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property));
837
1268
  if (prop && prop->children) {
838
1269
  for (cur = prop->children; cur; cur = cur->next) {
839
1270
  if (cur->_private) {
840
- nokogiri_root_node(cur);
1271
+ noko_xml_document_pin_node(cur);
841
1272
  xmlUnlinkNode(cur);
842
1273
  }
843
1274
  }
@@ -855,7 +1286,8 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
855
1286
  *
856
1287
  * Get the value for +attribute+
857
1288
  */
858
- static VALUE get(VALUE self, VALUE rattribute)
1289
+ static VALUE
1290
+ get(VALUE self, VALUE rattribute)
859
1291
  {
860
1292
  xmlNodePtr node;
861
1293
  xmlChar *value = 0;
@@ -866,10 +1298,10 @@ static VALUE get(VALUE self, VALUE rattribute)
866
1298
 
867
1299
  if (NIL_P(rattribute)) { return Qnil; }
868
1300
 
869
- Data_Get_Struct(self, xmlNode, node);
1301
+ Noko_Node_Get_Struct(self, xmlNode, node);
870
1302
  attribute = xmlCharStrdup(StringValueCStr(rattribute));
871
1303
 
872
- colon = (xmlChar *)(uintptr_t)xmlStrchr(attribute, (const xmlChar)':');
1304
+ colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':'));
873
1305
  if (colon) {
874
1306
  /* split the attribute string into separate prefix and name by
875
1307
  * null-terminating the prefix at the colon */
@@ -881,7 +1313,7 @@ static VALUE get(VALUE self, VALUE rattribute)
881
1313
  if (ns) {
882
1314
  value = xmlGetNsProp(node, attr_name, ns->href);
883
1315
  } else {
884
- value = xmlGetProp(node, (xmlChar*)StringValueCStr(rattribute));
1316
+ value = xmlGetProp(node, (xmlChar *)StringValueCStr(rattribute));
885
1317
  }
886
1318
  } else {
887
1319
  value = xmlGetNoNsProp(node, attribute);
@@ -902,15 +1334,16 @@ static VALUE get(VALUE self, VALUE rattribute)
902
1334
  *
903
1335
  * Set the namespace to +namespace+
904
1336
  */
905
- static VALUE set_namespace(VALUE self, VALUE namespace)
1337
+ static VALUE
1338
+ set_namespace(VALUE self, VALUE namespace)
906
1339
  {
907
1340
  xmlNodePtr node;
908
1341
  xmlNsPtr ns = NULL;
909
1342
 
910
- Data_Get_Struct(self, xmlNode, node);
1343
+ Noko_Node_Get_Struct(self, xmlNode, node);
911
1344
 
912
- if(!NIL_P(namespace)) {
913
- Data_Get_Struct(namespace, xmlNs, ns);
1345
+ if (!NIL_P(namespace)) {
1346
+ Noko_Namespace_Get_Struct(namespace, xmlNs, ns);
914
1347
  }
915
1348
 
916
1349
  xmlSetNs(node, ns);
@@ -919,138 +1352,140 @@ static VALUE set_namespace(VALUE self, VALUE namespace)
919
1352
  }
920
1353
 
921
1354
  /*
922
- * call-seq:
923
- * attribute(name)
1355
+ * :call-seq:
1356
+ * namespace() → Namespace
924
1357
  *
925
- * Get the attribute node with +name+
926
- */
927
- static VALUE attr(VALUE self, VALUE name)
928
- {
929
- xmlNodePtr node;
930
- xmlAttrPtr prop;
931
- Data_Get_Struct(self, xmlNode, node);
932
- prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
933
-
934
- if(! prop) { return Qnil; }
935
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
936
- }
937
-
938
- /*
939
- * call-seq:
940
- * attribute_with_ns(name, namespace)
1358
+ * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
941
1359
  *
942
- * Get the attribute node with +name+ and +namespace+
943
- */
944
- static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
945
- {
946
- xmlNodePtr node;
947
- xmlAttrPtr prop;
948
- Data_Get_Struct(self, xmlNode, node);
949
- prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
950
- NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
951
-
952
- if(! prop) { return Qnil; }
953
- return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
954
- }
955
-
956
- /*
957
- * call-seq:
958
- * attribute_nodes()
1360
+ * *Example:*
959
1361
  *
960
- * returns a list containing the Node attributes.
1362
+ * doc = Nokogiri::XML(<<~EOF)
1363
+ * <root>
1364
+ * <first/>
1365
+ * <second xmlns="http://example.com/child"/>
1366
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1367
+ * </root>
1368
+ * EOF
1369
+ * doc.at_xpath("//first").namespace
1370
+ * # => nil
1371
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
1372
+ * # => #(Namespace:0x3c { href = "http://example.com/child" })
1373
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
1374
+ * # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
961
1375
  */
962
- static VALUE attribute_nodes(VALUE self)
1376
+ static VALUE
1377
+ rb_xml_node_namespace(VALUE rb_node)
963
1378
  {
964
- /* this code in the mode of xmlHasProp() */
965
- xmlNodePtr node;
966
- VALUE attr;
1379
+ xmlNodePtr c_node ;
1380
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
967
1381
 
968
- Data_Get_Struct(self, xmlNode, node);
969
-
970
- attr = rb_ary_new();
971
- Nokogiri_xml_node_properties(node, attr);
1382
+ if (c_node->ns) {
1383
+ return noko_xml_namespace_wrap(c_node->ns, c_node->doc);
1384
+ }
972
1385
 
973
- return attr ;
1386
+ return Qnil ;
974
1387
  }
975
1388
 
976
-
977
1389
  /*
978
- * call-seq:
979
- * namespace()
1390
+ * :call-seq:
1391
+ * namespace_definitions() → Array<Nokogiri::XML::Namespace>
980
1392
  *
981
- * returns the namespace of the element or attribute node as a Namespace
982
- * object, or nil if there is no namespace for the element or attribute.
983
- */
984
- static VALUE namespace(VALUE self)
985
- {
986
- xmlNodePtr node ;
987
- Data_Get_Struct(self, xmlNode, node);
988
-
989
- if (node->ns) {
990
- return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
991
- }
992
-
993
- return Qnil ;
994
- }
995
-
996
- /*
997
- * call-seq:
998
- * namespace_definitions()
1393
+ * [Returns]
1394
+ * Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
1395
+ * will be empty if no namespaces are defined on this node.
999
1396
  *
1000
- * 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=").
1397
+ * *Example:*
1398
+ *
1399
+ * doc = Nokogiri::XML(<<~EOF)
1400
+ * <root xmlns="http://example.com/root">
1401
+ * <first/>
1402
+ * <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
1403
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1404
+ * </root>
1405
+ * EOF
1406
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
1407
+ * # => []
1408
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
1409
+ * # => [#(Namespace:0x3c { href = "http://example.com/child" }),
1410
+ * # #(Namespace:0x50 {
1411
+ * # prefix = "unused",
1412
+ * # href = "http://example.com/unused"
1413
+ * # })]
1414
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
1415
+ * # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
1001
1416
  */
1002
- static VALUE namespace_definitions(VALUE self)
1417
+ static VALUE
1418
+ namespace_definitions(VALUE rb_node)
1003
1419
  {
1004
1420
  /* this code in the mode of xmlHasProp() */
1005
- xmlNodePtr node ;
1006
- VALUE list;
1007
- xmlNsPtr ns;
1008
-
1009
- Data_Get_Struct(self, xmlNode, node);
1421
+ xmlNodePtr c_node ;
1422
+ xmlNsPtr c_namespace;
1423
+ VALUE definitions = rb_ary_new();
1010
1424
 
1011
- list = rb_ary_new();
1425
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
1012
1426
 
1013
- ns = node->nsDef;
1014
-
1015
- if(!ns) { return list; }
1427
+ c_namespace = c_node->nsDef;
1428
+ if (!c_namespace) {
1429
+ return definitions;
1430
+ }
1016
1431
 
1017
- while(NULL != ns) {
1018
- rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
1019
- ns = ns->next;
1432
+ while (c_namespace != NULL) {
1433
+ rb_ary_push(definitions, noko_xml_namespace_wrap(c_namespace, c_node->doc));
1434
+ c_namespace = c_namespace->next;
1020
1435
  }
1021
1436
 
1022
- return list;
1437
+ return definitions;
1023
1438
  }
1024
1439
 
1025
1440
  /*
1026
- * call-seq:
1027
- * namespace_scopes()
1441
+ * :call-seq:
1442
+ * namespace_scopes() → Array<Nokogiri::XML::Namespace>
1028
1443
  *
1029
- * returns namespaces in scope for self -- those defined on self element
1030
- * directly or any ancestor node -- as an array of Namespace objects. Default
1031
- * namespaces ("xmlns=" style) for self are included in this array; Default
1032
- * namespaces for ancestors, however, are not. See also #namespaces
1444
+ * [Returns] Array of all the Namespaces on this node and its ancestors.
1445
+ *
1446
+ * See also #namespaces
1447
+ *
1448
+ * *Example:*
1449
+ *
1450
+ * doc = Nokogiri::XML(<<~EOF)
1451
+ * <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
1452
+ * <first/>
1453
+ * <second xmlns="http://example.com/child"/>
1454
+ * <third xmlns:foo="http://example.com/foo"/>
1455
+ * </root>
1456
+ * EOF
1457
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
1458
+ * # => [#(Namespace:0x3c { href = "http://example.com/root" }),
1459
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1460
+ * doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
1461
+ * # => [#(Namespace:0x64 { href = "http://example.com/child" }),
1462
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1463
+ * doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
1464
+ * # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
1465
+ * # #(Namespace:0x3c { href = "http://example.com/root" }),
1466
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1033
1467
  */
1034
- static VALUE namespace_scopes(VALUE self)
1468
+ static VALUE
1469
+ rb_xml_node_namespace_scopes(VALUE rb_node)
1035
1470
  {
1036
- xmlNodePtr node ;
1037
- VALUE list;
1038
- xmlNsPtr *ns_list;
1471
+ xmlNodePtr c_node ;
1472
+ xmlNsPtr *namespaces;
1473
+ VALUE scopes = rb_ary_new();
1039
1474
  int j;
1040
1475
 
1041
- Data_Get_Struct(self, xmlNode, node);
1476
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
1042
1477
 
1043
- list = rb_ary_new();
1044
- ns_list = xmlGetNsList(node->doc, node);
1045
-
1046
- if(!ns_list) { return list; }
1478
+ namespaces = xmlGetNsList(c_node->doc, c_node);
1479
+ if (!namespaces) {
1480
+ return scopes;
1481
+ }
1047
1482
 
1048
- for (j = 0 ; ns_list[j] != NULL ; ++j) {
1049
- rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns_list[j]));
1483
+ for (j = 0 ; namespaces[j] != NULL ; ++j) {
1484
+ rb_ary_push(scopes, noko_xml_namespace_wrap(namespaces[j], c_node->doc));
1050
1485
  }
1051
1486
 
1052
- xmlFree(ns_list);
1053
- return list;
1487
+ xmlFree(namespaces);
1488
+ return scopes;
1054
1489
  }
1055
1490
 
1056
1491
  /*
@@ -1059,11 +1494,12 @@ static VALUE namespace_scopes(VALUE self)
1059
1494
  *
1060
1495
  * Get the type for this Node
1061
1496
  */
1062
- static VALUE node_type(VALUE self)
1497
+ static VALUE
1498
+ node_type(VALUE self)
1063
1499
  {
1064
1500
  xmlNodePtr node;
1065
- Data_Get_Struct(self, xmlNode, node);
1066
- return INT2NUM((long)node->type);
1501
+ Noko_Node_Get_Struct(self, xmlNode, node);
1502
+ return INT2NUM(node->type);
1067
1503
  }
1068
1504
 
1069
1505
  /*
@@ -1072,16 +1508,17 @@ static VALUE node_type(VALUE self)
1072
1508
  *
1073
1509
  * Set the content for this Node
1074
1510
  */
1075
- static VALUE set_native_content(VALUE self, VALUE content)
1511
+ static VALUE
1512
+ set_native_content(VALUE self, VALUE content)
1076
1513
  {
1077
1514
  xmlNodePtr node, child, next ;
1078
- Data_Get_Struct(self, xmlNode, node);
1515
+ Noko_Node_Get_Struct(self, xmlNode, node);
1079
1516
 
1080
1517
  child = node->children;
1081
1518
  while (NULL != child) {
1082
1519
  next = child->next ;
1083
1520
  xmlUnlinkNode(child) ;
1084
- nokogiri_root_node(child);
1521
+ noko_xml_document_pin_node(child);
1085
1522
  child = next ;
1086
1523
  }
1087
1524
 
@@ -1089,41 +1526,20 @@ static VALUE set_native_content(VALUE self, VALUE content)
1089
1526
  return content;
1090
1527
  }
1091
1528
 
1092
- /*
1093
- * call-seq:
1094
- * content
1095
- *
1096
- * Returns the content for this Node
1097
- */
1098
- static VALUE get_native_content(VALUE self)
1099
- {
1100
- xmlNodePtr node;
1101
- xmlChar * content;
1102
-
1103
- Data_Get_Struct(self, xmlNode, node);
1104
-
1105
- content = xmlNodeGetContent(node);
1106
- if(content) {
1107
- VALUE rval = NOKOGIRI_STR_NEW2(content);
1108
- xmlFree(content);
1109
- return rval;
1110
- }
1111
- return Qnil;
1112
- }
1113
-
1114
1529
  /*
1115
1530
  * call-seq:
1116
1531
  * lang=
1117
1532
  *
1118
1533
  * Set the language of a node, i.e. the values of the xml:lang attribute.
1119
1534
  */
1120
- static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
1535
+ static VALUE
1536
+ set_lang(VALUE self_rb, VALUE lang_rb)
1121
1537
  {
1122
1538
  xmlNodePtr self ;
1123
- xmlChar* lang ;
1539
+ xmlChar *lang ;
1124
1540
 
1125
- Data_Get_Struct(self_rb, xmlNode, self);
1126
- lang = (xmlChar*)StringValueCStr(lang_rb);
1541
+ Noko_Node_Get_Struct(self_rb, xmlNode, self);
1542
+ lang = (xmlChar *)StringValueCStr(lang_rb);
1127
1543
 
1128
1544
  xmlNodeSetLang(self, lang);
1129
1545
 
@@ -1137,13 +1553,14 @@ static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
1137
1553
  * Searches the language of a node, i.e. the values of the xml:lang attribute or
1138
1554
  * the one carried by the nearest ancestor.
1139
1555
  */
1140
- static VALUE get_lang(VALUE self_rb)
1556
+ static VALUE
1557
+ get_lang(VALUE self_rb)
1141
1558
  {
1142
1559
  xmlNodePtr self ;
1143
- xmlChar* lang ;
1560
+ xmlChar *lang ;
1144
1561
  VALUE lang_rb ;
1145
1562
 
1146
- Data_Get_Struct(self_rb, xmlNode, self);
1563
+ Noko_Node_Get_Struct(self_rb, xmlNode, self);
1147
1564
 
1148
1565
  lang = xmlNodeGetLang(self);
1149
1566
  if (lang) {
@@ -1156,7 +1573,8 @@ static VALUE get_lang(VALUE self_rb)
1156
1573
  }
1157
1574
 
1158
1575
  /* :nodoc: */
1159
- static VALUE add_child(VALUE self, VALUE new_child)
1576
+ static VALUE
1577
+ add_child(VALUE self, VALUE new_child)
1160
1578
  {
1161
1579
  return reparent_node_with(self, new_child, xmlAddChild);
1162
1580
  }
@@ -1167,15 +1585,16 @@ static VALUE add_child(VALUE self, VALUE new_child)
1167
1585
  *
1168
1586
  * Get the parent Node for this Node
1169
1587
  */
1170
- static VALUE get_parent(VALUE self)
1588
+ static VALUE
1589
+ get_parent(VALUE self)
1171
1590
  {
1172
1591
  xmlNodePtr node, parent;
1173
- Data_Get_Struct(self, xmlNode, node);
1592
+ Noko_Node_Get_Struct(self, xmlNode, node);
1174
1593
 
1175
1594
  parent = node->parent;
1176
- if(!parent) { return Qnil; }
1595
+ if (!parent) { return Qnil; }
1177
1596
 
1178
- return Nokogiri_wrap_xml_node(Qnil, parent) ;
1597
+ return noko_xml_node_wrap(Qnil, parent) ;
1179
1598
  }
1180
1599
 
1181
1600
  /*
@@ -1184,11 +1603,12 @@ static VALUE get_parent(VALUE self)
1184
1603
  *
1185
1604
  * Set the name for this Node
1186
1605
  */
1187
- static VALUE set_name(VALUE self, VALUE new_name)
1606
+ static VALUE
1607
+ set_name(VALUE self, VALUE new_name)
1188
1608
  {
1189
1609
  xmlNodePtr node;
1190
- Data_Get_Struct(self, xmlNode, node);
1191
- xmlNodeSetName(node, (xmlChar*)StringValueCStr(new_name));
1610
+ Noko_Node_Get_Struct(self, xmlNode, node);
1611
+ xmlNodeSetName(node, (xmlChar *)StringValueCStr(new_name));
1192
1612
  return new_name;
1193
1613
  }
1194
1614
 
@@ -1198,11 +1618,12 @@ static VALUE set_name(VALUE self, VALUE new_name)
1198
1618
  *
1199
1619
  * Returns the name for this Node
1200
1620
  */
1201
- static VALUE get_name(VALUE self)
1621
+ static VALUE
1622
+ get_name(VALUE self)
1202
1623
  {
1203
1624
  xmlNodePtr node;
1204
- Data_Get_Struct(self, xmlNode, node);
1205
- if(node->name) {
1625
+ Noko_Node_Get_Struct(self, xmlNode, node);
1626
+ if (node->name) {
1206
1627
  return NOKOGIRI_STR_NEW2(node->name);
1207
1628
  }
1208
1629
  return Qnil;
@@ -1214,28 +1635,39 @@ static VALUE get_name(VALUE self)
1214
1635
  *
1215
1636
  * Returns the path associated with this Node
1216
1637
  */
1217
- static VALUE path(VALUE self)
1638
+ static VALUE
1639
+ rb_xml_node_path(VALUE rb_node)
1218
1640
  {
1219
- xmlNodePtr node;
1220
- xmlChar *path ;
1641
+ xmlNodePtr c_node;
1642
+ xmlChar *c_path ;
1221
1643
  VALUE rval;
1222
1644
 
1223
- Data_Get_Struct(self, xmlNode, node);
1645
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
1646
+
1647
+ c_path = xmlGetNodePath(c_node);
1648
+ if (c_path == NULL) {
1649
+ // see https://github.com/sparklemotion/nokogiri/issues/2250
1650
+ // this behavior is clearly undesirable, but is what libxml <= 2.9.10 returned, and so we
1651
+ // do this for now to preserve the behavior across libxml2 versions.
1652
+ rval = NOKOGIRI_STR_NEW2("?");
1653
+ } else {
1654
+ rval = NOKOGIRI_STR_NEW2(c_path);
1655
+ xmlFree(c_path);
1656
+ }
1224
1657
 
1225
- path = xmlGetNodePath(node);
1226
- rval = NOKOGIRI_STR_NEW2(path);
1227
- xmlFree(path);
1228
1658
  return rval ;
1229
1659
  }
1230
1660
 
1231
1661
  /* :nodoc: */
1232
- static VALUE add_next_sibling(VALUE self, VALUE new_sibling)
1662
+ static VALUE
1663
+ add_next_sibling(VALUE self, VALUE new_sibling)
1233
1664
  {
1234
1665
  return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
1235
1666
  }
1236
1667
 
1237
1668
  /* :nodoc: */
1238
- static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
1669
+ static VALUE
1670
+ add_previous_sibling(VALUE self, VALUE new_sibling)
1239
1671
  {
1240
1672
  return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
1241
1673
  }
@@ -1246,7 +1678,8 @@ static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
1246
1678
  *
1247
1679
  * Write this Node to +io+ with +encoding+ and +options+
1248
1680
  */
1249
- static VALUE native_write_to(
1681
+ static VALUE
1682
+ native_write_to(
1250
1683
  VALUE self,
1251
1684
  VALUE io,
1252
1685
  VALUE encoding,
@@ -1255,10 +1688,10 @@ static VALUE native_write_to(
1255
1688
  )
1256
1689
  {
1257
1690
  xmlNodePtr node;
1258
- const char * before_indent;
1691
+ const char *before_indent;
1259
1692
  xmlSaveCtxtPtr savectx;
1260
1693
 
1261
- Data_Get_Struct(self, xmlNode, node);
1694
+ Noko_Node_Get_Struct(self, xmlNode, node);
1262
1695
 
1263
1696
  xmlIndentTreeOutput = 1;
1264
1697
 
@@ -1267,8 +1700,8 @@ static VALUE native_write_to(
1267
1700
  xmlTreeIndentString = StringValueCStr(indent_string);
1268
1701
 
1269
1702
  savectx = xmlSaveToIO(
1270
- (xmlOutputWriteCallback)io_write_callback,
1271
- (xmlOutputCloseCallback)io_close_callback,
1703
+ (xmlOutputWriteCallback)noko_io_write,
1704
+ (xmlOutputCloseCallback)noko_io_close,
1272
1705
  (void *)io,
1273
1706
  RTEST(encoding) ? StringValueCStr(encoding) : NULL,
1274
1707
  (int)NUM2INT(options)
@@ -1281,93 +1714,366 @@ static VALUE native_write_to(
1281
1714
  return io;
1282
1715
  }
1283
1716
 
1284
- /*
1285
- * call-seq:
1286
- * line
1287
- *
1288
- * Returns the line for this Node
1289
- */
1290
- static VALUE line(VALUE self)
1717
+
1718
+ static inline void
1719
+ output_partial_string(VALUE out, char const *str, size_t length)
1291
1720
  {
1292
- xmlNodePtr node;
1293
- Data_Get_Struct(self, xmlNode, node);
1721
+ if (length) {
1722
+ rb_enc_str_buf_cat(out, str, (long)length, rb_utf8_encoding());
1723
+ }
1724
+ }
1294
1725
 
1295
- return INT2NUM(xmlGetLineNo(node));
1726
+ static inline void
1727
+ output_char(VALUE out, char ch)
1728
+ {
1729
+ output_partial_string(out, &ch, 1);
1296
1730
  }
1297
1731
 
1298
- /*
1299
- * call-seq:
1300
- * add_namespace_definition(prefix, href)
1301
- *
1302
- * Adds a namespace definition with +prefix+ using +href+ value. The result is
1303
- * as if parsed XML for this node had included an attribute
1304
- * 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
1305
- * added by passing 'nil' for prefix. Namespaces added this way will not
1306
- * show up in #attributes, but they will be included as an xmlns attribute
1307
- * when the node is serialized to XML.
1308
- */
1309
- static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
1732
+ static inline void
1733
+ output_string(VALUE out, char const *str)
1310
1734
  {
1311
- xmlNodePtr node, namespacee;
1312
- xmlNsPtr ns;
1735
+ output_partial_string(out, str, strlen(str));
1736
+ }
1737
+
1738
+ static inline void
1739
+ output_tagname(VALUE out, xmlNodePtr elem)
1740
+ {
1741
+ // Elements in the HTML, MathML, and SVG namespaces do not use a namespace
1742
+ // prefix in the HTML syntax.
1743
+ char const *name = (char const *)elem->name;
1744
+ xmlNsPtr ns = elem->ns;
1745
+ if (ns && ns->href && ns->prefix
1746
+ && strcmp((char const *)ns->href, "http://www.w3.org/1999/xhtml")
1747
+ && strcmp((char const *)ns->href, "http://www.w3.org/1998/Math/MathML")
1748
+ && strcmp((char const *)ns->href, "http://www.w3.org/2000/svg")) {
1749
+ output_string(out, (char const *)elem->ns->prefix);
1750
+ output_char(out, ':');
1751
+ char const *colon = strchr(name, ':');
1752
+ if (colon) {
1753
+ name = colon + 1;
1754
+ }
1755
+ }
1756
+ output_string(out, name);
1757
+ }
1758
+
1759
+ static inline void
1760
+ output_attr_name(VALUE out, xmlAttrPtr attr)
1761
+ {
1762
+ xmlNsPtr ns = attr->ns;
1763
+ char const *name = (char const *)attr->name;
1764
+ if (ns && ns->href) {
1765
+ char const *uri = (char const *)ns->href;
1766
+ char const *localname = strchr(name, ':');
1767
+ if (localname) {
1768
+ ++localname;
1769
+ } else {
1770
+ localname = name;
1771
+ }
1772
+
1773
+ if (!strcmp(uri, "http://www.w3.org/XML/1998/namespace")) {
1774
+ output_string(out, "xml:");
1775
+ name = localname;
1776
+ } else if (!strcmp(uri, "http://www.w3.org/2000/xmlns/")) {
1777
+ // xmlns:xmlns -> xmlns
1778
+ // xmlns:foo -> xmlns:foo
1779
+ if (strcmp(localname, "xmlns")) {
1780
+ output_string(out, "xmlns:");
1781
+ }
1782
+ name = localname;
1783
+ } else if (!strcmp(uri, "http://www.w3.org/1999/xlink")) {
1784
+ output_string(out, "xlink:");
1785
+ name = localname;
1786
+ } else if (ns->prefix) {
1787
+ output_string(out, (char const *)ns->prefix);
1788
+ output_char(out, ':');
1789
+ name = localname;
1790
+ }
1791
+ }
1792
+ output_string(out, name);
1793
+ }
1794
+
1795
+ static void
1796
+ output_escaped_string(VALUE out, xmlChar const *start, bool attr)
1797
+ {
1798
+ xmlChar const *next = start;
1799
+ int ch;
1800
+
1801
+ while ((ch = *next) != 0) {
1802
+ char const *replacement = NULL;
1803
+ size_t replaced_bytes = 1;
1804
+ if (ch == '&') {
1805
+ replacement = "&amp;";
1806
+ } else if (ch == 0xC2 && next[1] == 0xA0) {
1807
+ // U+00A0 NO-BREAK SPACE has the UTF-8 encoding C2 A0.
1808
+ replacement = "&nbsp;";
1809
+ replaced_bytes = 2;
1810
+ } else if (attr && ch == '"') {
1811
+ replacement = "&quot;";
1812
+ } else if (!attr && ch == '<') {
1813
+ replacement = "&lt;";
1814
+ } else if (!attr && ch == '>') {
1815
+ replacement = "&gt;";
1816
+ } else {
1817
+ ++next;
1818
+ continue;
1819
+ }
1820
+ output_partial_string(out, (char const *)start, next - start);
1821
+ output_string(out, replacement);
1822
+ next += replaced_bytes;
1823
+ start = next;
1824
+ }
1825
+ output_partial_string(out, (char const *)start, next - start);
1826
+ }
1313
1827
 
1314
- Data_Get_Struct(self, xmlNode, node);
1315
- namespacee = node ;
1828
+ static bool
1829
+ should_prepend_newline(xmlNodePtr node)
1830
+ {
1831
+ char const *name = (char const *)node->name;
1832
+ xmlNodePtr child = node->children;
1833
+
1834
+ if (!name || !child || (strcmp(name, "pre") && strcmp(name, "textarea") && strcmp(name, "listing"))) {
1835
+ return false;
1836
+ }
1837
+
1838
+ return child->type == XML_TEXT_NODE && child->content && child->content[0] == '\n';
1839
+ }
1316
1840
 
1317
- ns = xmlSearchNs(
1318
- node->doc,
1319
- node,
1320
- (const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
1321
- );
1841
+ static VALUE
1842
+ rb_prepend_newline(VALUE self)
1843
+ {
1844
+ xmlNodePtr node;
1845
+ Noko_Node_Get_Struct(self, xmlNode, node);
1846
+ return should_prepend_newline(node) ? Qtrue : Qfalse;
1847
+ }
1322
1848
 
1323
- if(!ns) {
1324
- if (node->type != XML_ELEMENT_NODE) {
1325
- namespacee = node->parent;
1849
+ static bool
1850
+ is_one_of(xmlNodePtr node, char const *const *tagnames, size_t num_tagnames)
1851
+ {
1852
+ char const *name = (char const *)node->name;
1853
+ if (name == NULL) { // fragments don't have a name
1854
+ return false;
1855
+ }
1856
+ for (size_t idx = 0; idx < num_tagnames; ++idx) {
1857
+ if (!strcmp(name, tagnames[idx])) {
1858
+ return true;
1326
1859
  }
1327
- ns = xmlNewNs(
1328
- namespacee,
1329
- (const xmlChar *)StringValueCStr(href),
1330
- (const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
1331
- );
1332
1860
  }
1861
+ return false;
1862
+
1863
+ }
1864
+
1865
+ static void
1866
+ output_node(
1867
+ VALUE out,
1868
+ xmlNodePtr node,
1869
+ bool preserve_newline
1870
+ )
1871
+ {
1872
+ static char const *const VOID_ELEMENTS[] = {
1873
+ "area", "base", "basefont", "bgsound", "br", "col", "embed", "frame", "hr",
1874
+ "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr",
1875
+ };
1876
+
1877
+ static char const *const UNESCAPED_TEXT_ELEMENTS[] = {
1878
+ "style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript",
1879
+ };
1880
+
1881
+ switch (node->type) {
1882
+ case XML_ELEMENT_NODE:
1883
+ // Serialize the start tag.
1884
+ output_char(out, '<');
1885
+ output_tagname(out, node);
1886
+
1887
+ // Add attributes.
1888
+ for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
1889
+ output_char(out, ' ');
1890
+ output_attr_name(out, attr);
1891
+ if (attr->children) {
1892
+ output_string(out, "=\"");
1893
+ xmlChar *value = xmlNodeListGetString(attr->doc, attr->children, 1);
1894
+ output_escaped_string(out, value, true);
1895
+ xmlFree(value);
1896
+ output_char(out, '"');
1897
+ } else {
1898
+ // Output name=""
1899
+ output_string(out, "=\"\"");
1900
+ }
1901
+ }
1902
+ output_char(out, '>');
1903
+
1904
+ // Add children and end tag if element is not void.
1905
+ if (!is_one_of(node, VOID_ELEMENTS, sizeof VOID_ELEMENTS / sizeof VOID_ELEMENTS[0])) {
1906
+ if (preserve_newline && should_prepend_newline(node)) {
1907
+ output_char(out, '\n');
1908
+ }
1909
+ for (xmlNodePtr child = node->children; child; child = child->next) {
1910
+ output_node(out, child, preserve_newline);
1911
+ }
1912
+ output_string(out, "</");
1913
+ output_tagname(out, node);
1914
+ output_char(out, '>');
1915
+ }
1916
+ break;
1917
+
1918
+ case XML_TEXT_NODE:
1919
+ if (node->parent
1920
+ && is_one_of(node->parent, UNESCAPED_TEXT_ELEMENTS,
1921
+ sizeof UNESCAPED_TEXT_ELEMENTS / sizeof UNESCAPED_TEXT_ELEMENTS[0])) {
1922
+ output_string(out, (char const *)node->content);
1923
+ } else {
1924
+ output_escaped_string(out, node->content, false);
1925
+ }
1926
+ break;
1927
+
1928
+ case XML_CDATA_SECTION_NODE:
1929
+ output_string(out, "<![CDATA[");
1930
+ output_string(out, (char const *)node->content);
1931
+ output_string(out, "]]>");
1932
+ break;
1933
+
1934
+ case XML_COMMENT_NODE:
1935
+ output_string(out, "<!--");
1936
+ output_string(out, (char const *)node->content);
1937
+ output_string(out, "-->");
1938
+ break;
1939
+
1940
+ case XML_PI_NODE:
1941
+ output_string(out, "<?");
1942
+ output_string(out, (char const *)node->content);
1943
+ output_char(out, '>');
1944
+ break;
1945
+
1946
+ case XML_DOCUMENT_TYPE_NODE:
1947
+ case XML_DTD_NODE:
1948
+ output_string(out, "<!DOCTYPE ");
1949
+ output_string(out, (char const *)node->name);
1950
+ output_string(out, ">");
1951
+ break;
1952
+
1953
+ case XML_DOCUMENT_NODE:
1954
+ case XML_DOCUMENT_FRAG_NODE:
1955
+ case XML_HTML_DOCUMENT_NODE:
1956
+ for (xmlNodePtr child = node->children; child; child = child->next) {
1957
+ output_node(out, child, preserve_newline);
1958
+ }
1959
+ break;
1960
+
1961
+ default:
1962
+ rb_raise(rb_eRuntimeError, "Unsupported document node (%d); this is a bug in Nokogiri", node->type);
1963
+ break;
1964
+ }
1965
+ }
1333
1966
 
1334
- if (!ns) { return Qnil ; }
1967
+ static VALUE
1968
+ html_standard_serialize(
1969
+ VALUE self,
1970
+ VALUE preserve_newline
1971
+ )
1972
+ {
1973
+ xmlNodePtr node;
1974
+ Noko_Node_Get_Struct(self, xmlNode, node);
1975
+ VALUE output = rb_str_buf_new(4096);
1976
+ output_node(output, node, RTEST(preserve_newline));
1977
+ return output;
1978
+ }
1335
1979
 
1336
- if(NIL_P(prefix) || node != namespacee) { xmlSetNs(node, ns); }
1980
+ /*
1981
+ * :call-seq:
1982
+ * line() → Integer
1983
+ *
1984
+ * [Returns] The line number of this Node.
1985
+ *
1986
+ * ---
1987
+ *
1988
+ * <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
1989
+ *
1990
+ * Semantic differences:
1991
+ * - The CRuby method reflects the node's line number <i>in the parsed string</i>
1992
+ * - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
1993
+ * corrections have been applied
1994
+ *
1995
+ * Performance differences:
1996
+ * - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
1997
+ * (constant time)
1998
+ * - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
1999
+ * time, where n is the number of nodes before/above the element in the DOM)
2000
+ *
2001
+ * If you'd like to help improve the JRuby implementation, please review these issues and reach out
2002
+ * to the maintainers:
2003
+ * - https://github.com/sparklemotion/nokogiri/issues/1223
2004
+ * - https://github.com/sparklemotion/nokogiri/pull/2177
2005
+ * - https://github.com/sparklemotion/nokogiri/issues/2380
2006
+ */
2007
+ static VALUE
2008
+ rb_xml_node_line(VALUE rb_node)
2009
+ {
2010
+ xmlNodePtr c_node;
2011
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
1337
2012
 
1338
- return Nokogiri_wrap_xml_namespace(node->doc, ns);
2013
+ return LONG2NUM(xmlGetLineNo(c_node));
1339
2014
  }
1340
2015
 
1341
2016
  /*
1342
2017
  * call-seq:
1343
- * new(name, document)
2018
+ * line=(num)
1344
2019
  *
1345
- * Create a new node with +name+ sharing GC lifecycle with +document+
2020
+ * Sets the line for this Node. num must be less than 65535.
1346
2021
  */
1347
- static VALUE new(int argc, VALUE *argv, VALUE klass)
2022
+ static VALUE
2023
+ rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
1348
2024
  {
1349
- xmlDocPtr doc;
1350
- xmlNodePtr node;
1351
- VALUE name;
1352
- VALUE document;
2025
+ xmlNodePtr c_node;
2026
+ int line_number = NUM2INT(rb_line_number);
2027
+
2028
+ Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
2029
+
2030
+ // libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
2031
+ // search for "psvi" in SAX2.c and tree.c to learn more.
2032
+ if (line_number < 65535) {
2033
+ c_node->line = (short) line_number;
2034
+ } else {
2035
+ c_node->line = 65535;
2036
+ if (c_node->type == XML_TEXT_NODE) {
2037
+ c_node->psvi = (void *)(ptrdiff_t) line_number;
2038
+ }
2039
+ }
2040
+
2041
+ return rb_line_number;
2042
+ }
2043
+
2044
+ /* :nodoc: documented in lib/nokogiri/xml/node.rb */
2045
+ static VALUE
2046
+ rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
2047
+ {
2048
+ xmlNodePtr c_document_node;
2049
+ xmlNodePtr c_node;
2050
+ VALUE rb_name;
2051
+ VALUE rb_document_node;
1353
2052
  VALUE rest;
1354
2053
  VALUE rb_node;
1355
2054
 
1356
- rb_scan_args(argc, argv, "2*", &name, &document, &rest);
2055
+ rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
1357
2056
 
1358
- Data_Get_Struct(document, xmlDoc, doc);
2057
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
2058
+ rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
2059
+ }
2060
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
2061
+ // TODO: deprecate allowing Node
2062
+ NOKO_WARN_DEPRECATION("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.");
2063
+ }
2064
+ Noko_Node_Get_Struct(rb_document_node, xmlNode, c_document_node);
1359
2065
 
1360
- node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(name));
1361
- node->doc = doc->doc;
1362
- nokogiri_root_node(node);
2066
+ c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
2067
+ c_node->doc = c_document_node->doc;
2068
+ noko_xml_document_pin_node(c_node);
1363
2069
 
1364
- rb_node = Nokogiri_wrap_xml_node(
2070
+ rb_node = noko_xml_node_wrap(
1365
2071
  klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1366
- node
2072
+ c_node
1367
2073
  );
1368
2074
  rb_obj_call_init(rb_node, argc, argv);
1369
2075
 
1370
- if(rb_block_given_p()) { rb_yield(rb_node); }
2076
+ if (rb_block_given_p()) { rb_yield(rb_node); }
1371
2077
 
1372
2078
  return rb_node;
1373
2079
  }
@@ -1378,13 +2084,14 @@ static VALUE new(int argc, VALUE *argv, VALUE klass)
1378
2084
  *
1379
2085
  * Returns the Node as html.
1380
2086
  */
1381
- static VALUE dump_html(VALUE self)
2087
+ static VALUE
2088
+ dump_html(VALUE self)
1382
2089
  {
1383
2090
  xmlBufferPtr buf ;
1384
2091
  xmlNodePtr node ;
1385
2092
  VALUE html;
1386
2093
 
1387
- Data_Get_Struct(self, xmlNode, node);
2094
+ Noko_Node_Get_Struct(self, xmlNode, node);
1388
2095
 
1389
2096
  buf = xmlBufferCreate() ;
1390
2097
  htmlNodeDump(buf, node->doc, node);
@@ -1399,13 +2106,14 @@ static VALUE dump_html(VALUE self)
1399
2106
  *
1400
2107
  * Compare this Node to +other+ with respect to their Document
1401
2108
  */
1402
- static VALUE compare(VALUE self, VALUE _other)
2109
+ static VALUE
2110
+ compare(VALUE self, VALUE _other)
1403
2111
  {
1404
2112
  xmlNodePtr node, other;
1405
- Data_Get_Struct(self, xmlNode, node);
1406
- Data_Get_Struct(_other, xmlNode, other);
2113
+ Noko_Node_Get_Struct(self, xmlNode, node);
2114
+ Noko_Node_Get_Struct(_other, xmlNode, other);
1407
2115
 
1408
- return INT2NUM((long)xmlXPathCmpNodes(other, node));
2116
+ return INT2NUM(xmlXPathCmpNodes(other, node));
1409
2117
  }
1410
2118
 
1411
2119
 
@@ -1416,13 +2124,14 @@ static VALUE compare(VALUE self, VALUE _other)
1416
2124
  * Loads and substitutes all xinclude elements below the node. The
1417
2125
  * parser context will be initialized with +options+.
1418
2126
  */
1419
- static VALUE process_xincludes(VALUE self, VALUE options)
2127
+ static VALUE
2128
+ process_xincludes(VALUE self, VALUE options)
1420
2129
  {
1421
2130
  int rcode ;
1422
2131
  xmlNodePtr node;
1423
2132
  VALUE error_list = rb_ary_new();
1424
2133
 
1425
- Data_Get_Struct(self, xmlNode, node);
2134
+ Noko_Node_Get_Struct(self, xmlNode, node);
1426
2135
 
1427
2136
  xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
1428
2137
  rcode = xmlXIncludeProcessTreeFlags(node, (int)NUM2INT(options));
@@ -1432,7 +2141,7 @@ static VALUE process_xincludes(VALUE self, VALUE options)
1432
2141
  xmlErrorPtr error;
1433
2142
 
1434
2143
  error = xmlGetLastError();
1435
- if(error) {
2144
+ if (error) {
1436
2145
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
1437
2146
  } else {
1438
2147
  rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
@@ -1444,7 +2153,8 @@ static VALUE process_xincludes(VALUE self, VALUE options)
1444
2153
 
1445
2154
 
1446
2155
  /* TODO: DOCUMENT ME */
1447
- static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
2156
+ static VALUE
2157
+ in_context(VALUE self, VALUE _str, VALUE _options)
1448
2158
  {
1449
2159
  xmlNodePtr node, list = 0, tmp, child_iter, node_children, doc_children;
1450
2160
  xmlNodeSetPtr set;
@@ -1452,7 +2162,7 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1452
2162
  VALUE doc, err;
1453
2163
  int doc_is_empty;
1454
2164
 
1455
- Data_Get_Struct(self, xmlNode, node);
2165
+ Noko_Node_Get_Struct(self, xmlNode, node);
1456
2166
 
1457
2167
  doc = DOC_RUBY_OBJECT(node->doc);
1458
2168
  err = rb_iv_get(doc, "@errors");
@@ -1493,9 +2203,7 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1493
2203
  */
1494
2204
  child_iter = node->doc->children ;
1495
2205
  while (child_iter) {
1496
- if (child_iter->parent != (xmlNodePtr)node->doc) {
1497
- child_iter->parent = (xmlNodePtr)node->doc;
1498
- }
2206
+ child_iter->parent = (xmlNodePtr)node->doc;
1499
2207
  child_iter = child_iter->next;
1500
2208
  }
1501
2209
 
@@ -1505,12 +2213,17 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1505
2213
 
1506
2214
  xmlSetStructuredErrorFunc(NULL, NULL);
1507
2215
 
1508
- /* Workaround for a libxml2 bug where a parsing error may leave a broken
2216
+ /*
2217
+ * Workaround for a libxml2 bug where a parsing error may leave a broken
1509
2218
  * node reference in node->doc->children.
2219
+ *
2220
+ * https://bugzilla.gnome.org/show_bug.cgi?id=668155
2221
+ *
1510
2222
  * This workaround is limited to when a parse error occurs, the document
1511
2223
  * went from having no children to having children, and the context node is
1512
2224
  * part of a document fragment.
1513
- * https://bugzilla.gnome.org/show_bug.cgi?id=668155
2225
+ *
2226
+ * TODO: This was fixed in libxml 2.8.0 by 71a243d
1514
2227
  */
1515
2228
  if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
1516
2229
  child_iter = node;
@@ -1525,12 +2238,12 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1525
2238
 
1526
2239
  /* FIXME: This probably needs to handle more constants... */
1527
2240
  switch (error) {
1528
- case XML_ERR_INTERNAL_ERROR:
1529
- case XML_ERR_NO_MEMORY:
1530
- rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
1531
- break;
1532
- default:
1533
- break;
2241
+ case XML_ERR_INTERNAL_ERROR:
2242
+ case XML_ERR_NO_MEMORY:
2243
+ rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
2244
+ break;
2245
+ default:
2246
+ break;
1534
2247
  }
1535
2248
 
1536
2249
  set = xmlXPathNodeSetCreate(NULL);
@@ -1539,178 +2252,174 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1539
2252
  tmp = list->next;
1540
2253
  list->next = NULL;
1541
2254
  xmlXPathNodeSetAddUnique(set, list);
1542
- nokogiri_root_node(list);
2255
+ noko_xml_document_pin_node(list);
1543
2256
  list = tmp;
1544
2257
  }
1545
2258
 
1546
- return Nokogiri_wrap_xml_node_set(set, doc);
2259
+ return noko_xml_node_set_wrap(set, doc);
1547
2260
  }
1548
2261
 
1549
-
1550
- VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
2262
+ VALUE
2263
+ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1551
2264
  {
1552
- VALUE document = Qnil ;
1553
- VALUE node_cache = Qnil ;
1554
- VALUE rb_node = Qnil ;
2265
+ VALUE rb_document, rb_node_cache, rb_node;
1555
2266
  nokogiriTuplePtr node_has_a_document;
1556
- xmlDocPtr doc;
1557
- void (*mark_method)(xmlNodePtr) = NULL ;
2267
+ xmlDocPtr c_doc;
1558
2268
 
1559
- assert(node);
2269
+ assert(c_node);
1560
2270
 
1561
- if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE) {
1562
- return DOC_RUBY_OBJECT(node->doc);
2271
+ if (c_node->type == XML_DOCUMENT_NODE || c_node->type == XML_HTML_DOCUMENT_NODE) {
2272
+ return DOC_RUBY_OBJECT(c_node->doc);
1563
2273
  }
1564
2274
 
1565
- /* It's OK if the node doesn't have a fully-realized document (as in XML::Reader). */
1566
- /* see https://github.com/sparklemotion/nokogiri/issues/95 */
1567
- /* and https://github.com/sparklemotion/nokogiri/issues/439 */
1568
- doc = node->doc;
1569
- if (doc->type == XML_DOCUMENT_FRAG_NODE) { doc = doc->doc; }
1570
- node_has_a_document = DOC_RUBY_OBJECT_TEST(doc);
2275
+ c_doc = c_node->doc;
2276
+
2277
+ // Nodes yielded from XML::Reader don't have a fully-realized Document
2278
+ node_has_a_document = DOC_RUBY_OBJECT_TEST(c_doc);
1571
2279
 
1572
- if(node->_private && node_has_a_document) {
1573
- return (VALUE)node->_private;
2280
+ if (c_node->_private && node_has_a_document) {
2281
+ return (VALUE)c_node->_private;
1574
2282
  }
1575
2283
 
1576
- if(!RTEST(klass)) {
1577
- switch(node->type) {
1578
- case XML_ELEMENT_NODE:
1579
- klass = cNokogiriXmlElement;
1580
- break;
1581
- case XML_TEXT_NODE:
1582
- klass = cNokogiriXmlText;
1583
- break;
1584
- case XML_ATTRIBUTE_NODE:
1585
- klass = cNokogiriXmlAttr;
1586
- break;
1587
- case XML_ENTITY_REF_NODE:
1588
- klass = cNokogiriXmlEntityReference;
1589
- break;
1590
- case XML_COMMENT_NODE:
1591
- klass = cNokogiriXmlComment;
1592
- break;
1593
- case XML_DOCUMENT_FRAG_NODE:
1594
- klass = cNokogiriXmlDocumentFragment;
1595
- break;
1596
- case XML_PI_NODE:
1597
- klass = cNokogiriXmlProcessingInstruction;
1598
- break;
1599
- case XML_ENTITY_DECL:
1600
- klass = cNokogiriXmlEntityDecl;
1601
- break;
1602
- case XML_CDATA_SECTION_NODE:
1603
- klass = cNokogiriXmlCData;
1604
- break;
1605
- case XML_DTD_NODE:
1606
- klass = cNokogiriXmlDtd;
1607
- break;
1608
- case XML_ATTRIBUTE_DECL:
1609
- klass = cNokogiriXmlAttributeDecl;
1610
- break;
1611
- case XML_ELEMENT_DECL:
1612
- klass = cNokogiriXmlElementDecl;
1613
- break;
1614
- default:
1615
- klass = cNokogiriXmlNode;
2284
+ if (!RTEST(rb_class)) {
2285
+ switch (c_node->type) {
2286
+ case XML_ELEMENT_NODE:
2287
+ rb_class = cNokogiriXmlElement;
2288
+ break;
2289
+ case XML_TEXT_NODE:
2290
+ rb_class = cNokogiriXmlText;
2291
+ break;
2292
+ case XML_ATTRIBUTE_NODE:
2293
+ rb_class = cNokogiriXmlAttr;
2294
+ break;
2295
+ case XML_ENTITY_REF_NODE:
2296
+ rb_class = cNokogiriXmlEntityReference;
2297
+ break;
2298
+ case XML_COMMENT_NODE:
2299
+ rb_class = cNokogiriXmlComment;
2300
+ break;
2301
+ case XML_DOCUMENT_FRAG_NODE:
2302
+ rb_class = cNokogiriXmlDocumentFragment;
2303
+ break;
2304
+ case XML_PI_NODE:
2305
+ rb_class = cNokogiriXmlProcessingInstruction;
2306
+ break;
2307
+ case XML_ENTITY_DECL:
2308
+ rb_class = cNokogiriXmlEntityDecl;
2309
+ break;
2310
+ case XML_CDATA_SECTION_NODE:
2311
+ rb_class = cNokogiriXmlCData;
2312
+ break;
2313
+ case XML_DTD_NODE:
2314
+ rb_class = cNokogiriXmlDtd;
2315
+ break;
2316
+ case XML_ATTRIBUTE_DECL:
2317
+ rb_class = cNokogiriXmlAttributeDecl;
2318
+ break;
2319
+ case XML_ELEMENT_DECL:
2320
+ rb_class = cNokogiriXmlElementDecl;
2321
+ break;
2322
+ default:
2323
+ rb_class = cNokogiriXmlNode;
1616
2324
  }
1617
2325
  }
1618
2326
 
1619
- mark_method = node_has_a_document ? mark : NULL ;
1620
-
1621
- rb_node = Data_Wrap_Struct(klass, mark_method, debug_node_dealloc, node) ;
1622
- node->_private = (void *)rb_node;
2327
+ rb_node = TypedData_Wrap_Struct(rb_class, &nokogiri_node_type, c_node) ;
2328
+ c_node->_private = (void *)rb_node;
1623
2329
 
1624
2330
  if (node_has_a_document) {
1625
- document = DOC_RUBY_OBJECT(doc);
1626
- node_cache = DOC_NODE_CACHE(doc);
1627
- rb_ary_push(node_cache, rb_node);
1628
- rb_funcall(document, decorate, 1, rb_node);
2331
+ rb_document = DOC_RUBY_OBJECT(c_doc);
2332
+ rb_node_cache = DOC_NODE_CACHE(c_doc);
2333
+ rb_ary_push(rb_node_cache, rb_node);
2334
+ rb_funcall(rb_document, id_decorate, 1, rb_node);
1629
2335
  }
1630
2336
 
1631
2337
  return rb_node ;
1632
2338
  }
1633
2339
 
1634
2340
 
1635
- void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
2341
+ /*
2342
+ * return Array<Nokogiri::XML::Attr> containing the node's attributes
2343
+ */
2344
+ VALUE
2345
+ noko_xml_node_attrs(xmlNodePtr c_node)
1636
2346
  {
1637
- xmlAttrPtr prop;
1638
- prop = node->properties ;
1639
- while (prop != NULL) {
1640
- rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
1641
- prop = prop->next ;
2347
+ VALUE rb_properties = rb_ary_new();
2348
+ xmlAttrPtr c_property;
2349
+
2350
+ c_property = c_node->properties ;
2351
+ while (c_property != NULL) {
2352
+ rb_ary_push(rb_properties, noko_xml_node_wrap(Qnil, (xmlNodePtr)c_property));
2353
+ c_property = c_property->next ;
1642
2354
  }
2355
+
2356
+ return rb_properties;
1643
2357
  }
1644
2358
 
1645
- VALUE cNokogiriXmlNode ;
1646
- VALUE cNokogiriXmlElement ;
1647
-
1648
- void init_xml_node()
1649
- {
1650
- VALUE nokogiri = rb_define_module("Nokogiri");
1651
- VALUE xml = rb_define_module_under(nokogiri, "XML");
1652
- VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
1653
-
1654
- cNokogiriXmlNode = klass;
1655
-
1656
- cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
1657
-
1658
- rb_define_singleton_method(klass, "new", new, -1);
1659
-
1660
- rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
1661
- rb_define_method(klass, "node_name", get_name, 0);
1662
- rb_define_method(klass, "document", document, 0);
1663
- rb_define_method(klass, "node_name=", set_name, 1);
1664
- rb_define_method(klass, "parent", get_parent, 0);
1665
- rb_define_method(klass, "child", child, 0);
1666
- rb_define_method(klass, "first_element_child", first_element_child, 0);
1667
- rb_define_method(klass, "last_element_child", last_element_child, 0);
1668
- rb_define_method(klass, "children", children, 0);
1669
- rb_define_method(klass, "element_children", element_children, 0);
1670
- rb_define_method(klass, "next_sibling", next_sibling, 0);
1671
- rb_define_method(klass, "previous_sibling", previous_sibling, 0);
1672
- rb_define_method(klass, "next_element", next_element, 0);
1673
- rb_define_method(klass, "previous_element", previous_element, 0);
1674
- rb_define_method(klass, "node_type", node_type, 0);
1675
- rb_define_method(klass, "path", path, 0);
1676
- rb_define_method(klass, "key?", key_eh, 1);
1677
- rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
1678
- rb_define_method(klass, "blank?", blank_eh, 0);
1679
- rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
1680
- rb_define_method(klass, "attribute", attr, 1);
1681
- rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
1682
- rb_define_method(klass, "namespace", namespace, 0);
1683
- rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
1684
- rb_define_method(klass, "namespace_scopes", namespace_scopes, 0);
1685
- rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
1686
- rb_define_method(klass, "dup", duplicate_node, -1);
1687
- rb_define_method(klass, "unlink", unlink_node, 0);
1688
- rb_define_method(klass, "internal_subset", internal_subset, 0);
1689
- rb_define_method(klass, "external_subset", external_subset, 0);
1690
- rb_define_method(klass, "create_internal_subset", create_internal_subset, 3);
1691
- rb_define_method(klass, "create_external_subset", create_external_subset, 3);
1692
- rb_define_method(klass, "pointer_id", pointer_id, 0);
1693
- rb_define_method(klass, "line", line, 0);
1694
- rb_define_method(klass, "content", get_native_content, 0);
1695
- rb_define_method(klass, "native_content=", set_native_content, 1);
1696
- rb_define_method(klass, "lang", get_lang, 0);
1697
- rb_define_method(klass, "lang=", set_lang, 1);
1698
-
1699
- rb_define_private_method(klass, "process_xincludes", process_xincludes, 1);
1700
- rb_define_private_method(klass, "in_context", in_context, 2);
1701
- rb_define_private_method(klass, "add_child_node", add_child, 1);
1702
- rb_define_private_method(klass, "add_previous_sibling_node", add_previous_sibling, 1);
1703
- rb_define_private_method(klass, "add_next_sibling_node", add_next_sibling, 1);
1704
- rb_define_private_method(klass, "replace_node", replace, 1);
1705
- rb_define_private_method(klass, "dump_html", dump_html, 0);
1706
- rb_define_private_method(klass, "native_write_to", native_write_to, 4);
1707
- rb_define_private_method(klass, "get", get, 1);
1708
- rb_define_private_method(klass, "set", set, 2);
1709
- rb_define_private_method(klass, "set_namespace", set_namespace, 1);
1710
- rb_define_private_method(klass, "compare", compare, 1);
1711
-
1712
- decorate = rb_intern("decorate");
1713
- decorate_bang = rb_intern("decorate!");
1714
- }
1715
-
1716
- /* vim: set noet sw=4 sws=4 */
2359
+ void
2360
+ noko_init_xml_node(void)
2361
+ {
2362
+ cNokogiriXmlNode = rb_define_class_under(mNokogiriXml, "Node", rb_cObject);
2363
+
2364
+ rb_undef_alloc_func(cNokogiriXmlNode);
2365
+
2366
+ rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
2367
+
2368
+ rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
2369
+ rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
2370
+ rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
2371
+ rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
2372
+ rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
2373
+ rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
2374
+ rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
2375
+ rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
2376
+ rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
2377
+ rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
2378
+ rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
2379
+ rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2380
+ rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
2381
+ rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
2382
+ rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
2383
+ rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
2384
+ rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
2385
+ rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
2386
+ rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
2387
+ rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
2388
+ rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
2389
+ rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
2390
+ rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
2391
+ rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
2392
+ rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
2393
+ rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
2394
+ rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
2395
+ rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
2396
+ rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
2397
+ rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
2398
+ rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
2399
+ rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
2400
+ rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
2401
+ rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
2402
+ rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
2403
+ rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
2404
+ rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
2405
+ rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
2406
+ rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
2407
+
2408
+ rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
2409
+ rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
2410
+ rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
2411
+ rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
2412
+ rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
2413
+ rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
2414
+ rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
2415
+ rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
2416
+ rb_define_private_method(cNokogiriXmlNode, "prepend_newline?", rb_prepend_newline, 0);
2417
+ rb_define_private_method(cNokogiriXmlNode, "html_standard_serialize", html_standard_serialize, 1);
2418
+ rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
2419
+ rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
2420
+ rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
2421
+ rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
2422
+
2423
+ id_decorate = rb_intern("decorate");
2424
+ id_decorate_bang = rb_intern("decorate!");
2425
+ }