nokogiri 1.8.5 → 1.13.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

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