nokogiri 1.8.5 → 1.13.9

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