nokogiri 1.2.3-x86-mswin32-60 → 1.4.5-x86-mswin32-60

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 (319) hide show
  1. data/.autotest +18 -7
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.ja.rdoc +297 -3
  4. data/CHANGELOG.rdoc +289 -0
  5. data/Manifest.txt +148 -37
  6. data/README.ja.rdoc +20 -20
  7. data/README.rdoc +53 -22
  8. data/Rakefile +127 -211
  9. data/bin/nokogiri +54 -0
  10. data/ext/nokogiri/depend +358 -0
  11. data/ext/nokogiri/extconf.rb +89 -54
  12. data/ext/nokogiri/html_document.c +34 -27
  13. data/ext/nokogiri/html_document.h +1 -1
  14. data/ext/nokogiri/html_element_description.c +276 -0
  15. data/ext/nokogiri/html_element_description.h +10 -0
  16. data/ext/nokogiri/html_entity_lookup.c +7 -5
  17. data/ext/nokogiri/html_entity_lookup.h +1 -1
  18. data/ext/nokogiri/html_sax_parser_context.c +94 -0
  19. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  20. data/ext/nokogiri/{native.c → nokogiri.c} +31 -7
  21. data/ext/nokogiri/{native.h → nokogiri.h} +68 -41
  22. data/ext/nokogiri/xml_attr.c +20 -9
  23. data/ext/nokogiri/xml_attr.h +1 -1
  24. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  25. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  26. data/ext/nokogiri/xml_cdata.c +21 -9
  27. data/ext/nokogiri/xml_cdata.h +1 -1
  28. data/ext/nokogiri/xml_comment.c +18 -6
  29. data/ext/nokogiri/xml_comment.h +1 -1
  30. data/ext/nokogiri/xml_document.c +247 -68
  31. data/ext/nokogiri/xml_document.h +5 -3
  32. data/ext/nokogiri/xml_document_fragment.c +15 -7
  33. data/ext/nokogiri/xml_document_fragment.h +1 -1
  34. data/ext/nokogiri/xml_dtd.c +110 -10
  35. data/ext/nokogiri/xml_dtd.h +3 -1
  36. data/ext/nokogiri/xml_element_content.c +123 -0
  37. data/ext/nokogiri/xml_element_content.h +10 -0
  38. data/ext/nokogiri/xml_element_decl.c +69 -0
  39. data/ext/nokogiri/xml_element_decl.h +9 -0
  40. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  41. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  42. data/ext/nokogiri/xml_entity_decl.c +110 -0
  43. data/ext/nokogiri/xml_entity_decl.h +10 -0
  44. data/ext/nokogiri/xml_entity_reference.c +16 -5
  45. data/ext/nokogiri/xml_entity_reference.h +1 -1
  46. data/ext/nokogiri/xml_io.c +40 -8
  47. data/ext/nokogiri/xml_io.h +2 -1
  48. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  49. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  50. data/ext/nokogiri/xml_namespace.c +84 -0
  51. data/ext/nokogiri/xml_namespace.h +13 -0
  52. data/ext/nokogiri/xml_node.c +782 -225
  53. data/ext/nokogiri/xml_node.h +2 -4
  54. data/ext/nokogiri/xml_node_set.c +253 -34
  55. data/ext/nokogiri/xml_node_set.h +2 -2
  56. data/ext/nokogiri/xml_processing_instruction.c +17 -5
  57. data/ext/nokogiri/xml_processing_instruction.h +1 -1
  58. data/ext/nokogiri/xml_reader.c +277 -85
  59. data/ext/nokogiri/xml_reader.h +1 -1
  60. data/ext/nokogiri/xml_relax_ng.c +168 -0
  61. data/ext/nokogiri/xml_relax_ng.h +9 -0
  62. data/ext/nokogiri/xml_sax_parser.c +183 -111
  63. data/ext/nokogiri/xml_sax_parser.h +30 -1
  64. data/ext/nokogiri/xml_sax_parser_context.c +199 -0
  65. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  66. data/ext/nokogiri/xml_sax_push_parser.c +42 -12
  67. data/ext/nokogiri/xml_sax_push_parser.h +1 -1
  68. data/ext/nokogiri/xml_schema.c +205 -0
  69. data/ext/nokogiri/xml_schema.h +9 -0
  70. data/ext/nokogiri/xml_syntax_error.c +28 -173
  71. data/ext/nokogiri/xml_syntax_error.h +2 -1
  72. data/ext/nokogiri/xml_text.c +16 -6
  73. data/ext/nokogiri/xml_text.h +1 -1
  74. data/ext/nokogiri/xml_xpath_context.c +104 -47
  75. data/ext/nokogiri/xml_xpath_context.h +1 -1
  76. data/ext/nokogiri/xslt_stylesheet.c +161 -19
  77. data/ext/nokogiri/xslt_stylesheet.h +1 -1
  78. data/lib/nokogiri.rb +47 -8
  79. data/lib/nokogiri/1.8/nokogiri.so +0 -0
  80. data/lib/nokogiri/1.9/nokogiri.so +0 -0
  81. data/lib/nokogiri/css.rb +6 -3
  82. data/lib/nokogiri/css/node.rb +14 -12
  83. data/lib/nokogiri/css/parser.rb +665 -62
  84. data/lib/nokogiri/css/parser.y +20 -10
  85. data/lib/nokogiri/css/parser_extras.rb +91 -0
  86. data/lib/nokogiri/css/tokenizer.rb +148 -5
  87. data/lib/nokogiri/css/tokenizer.rex +10 -9
  88. data/lib/nokogiri/css/xpath_visitor.rb +47 -44
  89. data/lib/nokogiri/decorators/slop.rb +8 -4
  90. data/lib/nokogiri/ffi/encoding_handler.rb +42 -0
  91. data/lib/nokogiri/ffi/html/document.rb +28 -0
  92. data/lib/nokogiri/ffi/html/element_description.rb +81 -0
  93. data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
  94. data/lib/nokogiri/ffi/html/sax/parser_context.rb +38 -0
  95. data/lib/nokogiri/ffi/io_callbacks.rb +42 -0
  96. data/lib/nokogiri/ffi/libxml.rb +420 -0
  97. data/lib/nokogiri/ffi/structs/common_node.rb +38 -0
  98. data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
  99. data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
  100. data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
  101. data/lib/nokogiri/ffi/structs/xml_attr.rb +20 -0
  102. data/lib/nokogiri/ffi/structs/xml_attribute.rb +27 -0
  103. data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
  104. data/lib/nokogiri/ffi/structs/xml_char_encoding_handler.rb +11 -0
  105. data/lib/nokogiri/ffi/structs/xml_document.rb +117 -0
  106. data/lib/nokogiri/ffi/structs/xml_dtd.rb +28 -0
  107. data/lib/nokogiri/ffi/structs/xml_element.rb +26 -0
  108. data/lib/nokogiri/ffi/structs/xml_element_content.rb +17 -0
  109. data/lib/nokogiri/ffi/structs/xml_entity.rb +32 -0
  110. data/lib/nokogiri/ffi/structs/xml_enumeration.rb +12 -0
  111. data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
  112. data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
  113. data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
  114. data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
  115. data/lib/nokogiri/ffi/structs/xml_parser_context.rb +20 -0
  116. data/lib/nokogiri/ffi/structs/xml_parser_input.rb +19 -0
  117. data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
  118. data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
  119. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +124 -0
  120. data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
  121. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
  122. data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
  123. data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +38 -0
  124. data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
  125. data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
  126. data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
  127. data/lib/nokogiri/ffi/weak_bucket.rb +40 -0
  128. data/lib/nokogiri/ffi/xml/attr.rb +41 -0
  129. data/lib/nokogiri/ffi/xml/attribute_decl.rb +27 -0
  130. data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
  131. data/lib/nokogiri/ffi/xml/comment.rb +18 -0
  132. data/lib/nokogiri/ffi/xml/document.rb +174 -0
  133. data/lib/nokogiri/ffi/xml/document_fragment.rb +21 -0
  134. data/lib/nokogiri/ffi/xml/dtd.rb +67 -0
  135. data/lib/nokogiri/ffi/xml/element_content.rb +43 -0
  136. data/lib/nokogiri/ffi/xml/element_decl.rb +19 -0
  137. data/lib/nokogiri/ffi/xml/entity_decl.rb +36 -0
  138. data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
  139. data/lib/nokogiri/ffi/xml/namespace.rb +44 -0
  140. data/lib/nokogiri/ffi/xml/node.rb +559 -0
  141. data/lib/nokogiri/ffi/xml/node_set.rb +150 -0
  142. data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
  143. data/lib/nokogiri/ffi/xml/reader.rb +236 -0
  144. data/lib/nokogiri/ffi/xml/relax_ng.rb +85 -0
  145. data/lib/nokogiri/ffi/xml/sax/parser.rb +143 -0
  146. data/lib/nokogiri/ffi/xml/sax/parser_context.rb +79 -0
  147. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +51 -0
  148. data/lib/nokogiri/ffi/xml/schema.rb +109 -0
  149. data/lib/nokogiri/ffi/xml/syntax_error.rb +98 -0
  150. data/lib/nokogiri/ffi/xml/text.rb +18 -0
  151. data/lib/nokogiri/ffi/xml/xpath.rb +9 -0
  152. data/lib/nokogiri/ffi/xml/xpath_context.rb +153 -0
  153. data/lib/nokogiri/ffi/xslt/stylesheet.rb +77 -0
  154. data/lib/nokogiri/html.rb +13 -47
  155. data/lib/nokogiri/html/builder.rb +27 -1
  156. data/lib/nokogiri/html/document.rb +201 -7
  157. data/lib/nokogiri/html/document_fragment.rb +41 -0
  158. data/lib/nokogiri/html/element_description.rb +23 -0
  159. data/lib/nokogiri/html/entity_lookup.rb +2 -0
  160. data/lib/nokogiri/html/sax/parser.rb +34 -3
  161. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  162. data/lib/nokogiri/nokogiri.rb +1 -0
  163. data/lib/nokogiri/version.rb +40 -1
  164. data/lib/nokogiri/version_warning.rb +14 -0
  165. data/lib/nokogiri/xml.rb +32 -53
  166. data/lib/nokogiri/xml/attr.rb +5 -0
  167. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  168. data/lib/nokogiri/xml/builder.rb +349 -29
  169. data/lib/nokogiri/xml/cdata.rb +3 -1
  170. data/lib/nokogiri/xml/character_data.rb +7 -0
  171. data/lib/nokogiri/xml/document.rb +166 -14
  172. data/lib/nokogiri/xml/document_fragment.rb +76 -1
  173. data/lib/nokogiri/xml/dtd.rb +16 -3
  174. data/lib/nokogiri/xml/element_content.rb +36 -0
  175. data/lib/nokogiri/xml/element_decl.rb +13 -0
  176. data/lib/nokogiri/xml/entity_decl.rb +19 -0
  177. data/lib/nokogiri/xml/namespace.rb +13 -0
  178. data/lib/nokogiri/xml/node.rb +561 -166
  179. data/lib/nokogiri/xml/node/save_options.rb +22 -2
  180. data/lib/nokogiri/xml/node_set.rb +202 -40
  181. data/lib/nokogiri/xml/parse_options.rb +93 -0
  182. data/lib/nokogiri/xml/pp.rb +2 -0
  183. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  184. data/lib/nokogiri/xml/pp/node.rb +56 -0
  185. data/lib/nokogiri/xml/processing_instruction.rb +2 -0
  186. data/lib/nokogiri/xml/reader.rb +93 -8
  187. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  188. data/lib/nokogiri/xml/sax.rb +1 -7
  189. data/lib/nokogiri/xml/sax/document.rb +107 -2
  190. data/lib/nokogiri/xml/sax/parser.rb +57 -7
  191. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  192. data/lib/nokogiri/xml/sax/push_parser.rb +13 -1
  193. data/lib/nokogiri/xml/schema.rb +63 -0
  194. data/lib/nokogiri/xml/syntax_error.rb +25 -1
  195. data/lib/nokogiri/xml/text.rb +4 -1
  196. data/lib/nokogiri/xml/xpath.rb +1 -1
  197. data/lib/nokogiri/xml/xpath/syntax_error.rb +3 -0
  198. data/lib/nokogiri/xml/xpath_context.rb +2 -0
  199. data/lib/nokogiri/xslt.rb +26 -2
  200. data/lib/nokogiri/xslt/stylesheet.rb +19 -0
  201. data/lib/xsd/xmlparser/nokogiri.rb +45 -9
  202. data/tasks/cross_compile.rb +173 -0
  203. data/tasks/test.rb +25 -69
  204. data/test/css/test_nthiness.rb +3 -4
  205. data/test/css/test_parser.rb +75 -20
  206. data/test/css/test_tokenizer.rb +23 -1
  207. data/test/css/test_xpath_visitor.rb +10 -1
  208. data/test/decorators/test_slop.rb +16 -0
  209. data/test/ffi/test_document.rb +35 -0
  210. data/test/files/2ch.html +108 -0
  211. data/test/files/address_book.rlx +12 -0
  212. data/test/files/address_book.xml +10 -0
  213. data/test/files/bar/bar.xsd +4 -0
  214. data/test/files/encoding.html +82 -0
  215. data/test/files/encoding.xhtml +84 -0
  216. data/test/files/foo/foo.xsd +4 -0
  217. data/test/files/po.xml +32 -0
  218. data/test/files/po.xsd +66 -0
  219. data/test/files/shift_jis.html +10 -0
  220. data/test/files/shift_jis.xml +5 -0
  221. data/test/files/snuggles.xml +3 -0
  222. data/test/files/staff.dtd +10 -0
  223. data/test/files/valid_bar.xml +2 -0
  224. data/test/helper.rb +101 -23
  225. data/test/html/sax/test_parser.rb +81 -2
  226. data/test/html/sax/test_parser_context.rb +48 -0
  227. data/test/html/test_builder.rb +39 -8
  228. data/test/html/test_document.rb +186 -23
  229. data/test/html/test_document_encoding.rb +78 -1
  230. data/test/html/test_document_fragment.rb +253 -0
  231. data/test/html/test_element_description.rb +98 -0
  232. data/test/html/test_named_characters.rb +1 -1
  233. data/test/html/test_node.rb +124 -36
  234. data/test/html/test_node_encoding.rb +27 -0
  235. data/test/test_convert_xpath.rb +1 -52
  236. data/test/test_css_cache.rb +2 -13
  237. data/test/test_encoding_handler.rb +46 -0
  238. data/test/test_memory_leak.rb +88 -19
  239. data/test/test_nokogiri.rb +38 -5
  240. data/test/test_reader.rb +188 -6
  241. data/test/test_soap4r_sax.rb +52 -0
  242. data/test/test_xslt_transforms.rb +183 -83
  243. data/test/xml/node/test_save_options.rb +1 -1
  244. data/test/xml/node/test_subclass.rb +44 -0
  245. data/test/xml/sax/test_parser.rb +175 -4
  246. data/test/xml/sax/test_parser_context.rb +113 -0
  247. data/test/xml/sax/test_push_parser.rb +90 -2
  248. data/test/xml/test_attr.rb +35 -1
  249. data/test/xml/test_attribute_decl.rb +82 -0
  250. data/test/xml/test_builder.rb +186 -1
  251. data/test/xml/test_cdata.rb +32 -1
  252. data/test/xml/test_comment.rb +13 -1
  253. data/test/xml/test_document.rb +415 -43
  254. data/test/xml/test_document_encoding.rb +1 -1
  255. data/test/xml/test_document_fragment.rb +173 -5
  256. data/test/xml/test_dtd.rb +61 -6
  257. data/test/xml/test_dtd_encoding.rb +3 -1
  258. data/test/xml/test_element_content.rb +56 -0
  259. data/test/xml/test_element_decl.rb +73 -0
  260. data/test/xml/test_entity_decl.rb +120 -0
  261. data/test/xml/test_entity_reference.rb +5 -1
  262. data/test/xml/test_namespace.rb +68 -0
  263. data/test/xml/test_node.rb +546 -201
  264. data/test/xml/test_node_attributes.rb +34 -0
  265. data/test/xml/test_node_encoding.rb +33 -3
  266. data/test/xml/test_node_reparenting.rb +321 -0
  267. data/test/xml/test_node_set.rb +538 -2
  268. data/test/xml/test_parse_options.rb +52 -0
  269. data/test/xml/test_processing_instruction.rb +6 -1
  270. data/test/xml/test_reader_encoding.rb +1 -1
  271. data/test/xml/test_relax_ng.rb +60 -0
  272. data/test/xml/test_schema.rb +94 -0
  273. data/test/xml/test_syntax_error.rb +12 -0
  274. data/test/xml/test_text.rb +35 -1
  275. data/test/xml/test_unparented_node.rb +5 -5
  276. data/test/xml/test_xpath.rb +142 -11
  277. data/test/xslt/test_custom_functions.rb +94 -0
  278. metadata +328 -92
  279. data/ext/nokogiri/html_sax_parser.c +0 -57
  280. data/ext/nokogiri/html_sax_parser.h +0 -11
  281. data/ext/nokogiri/iconv.dll +0 -0
  282. data/ext/nokogiri/libexslt.dll +0 -0
  283. data/ext/nokogiri/libxml2.dll +0 -0
  284. data/ext/nokogiri/libxslt.dll +0 -0
  285. data/ext/nokogiri/native.so +0 -0
  286. data/ext/nokogiri/xml_xpath.c +0 -53
  287. data/ext/nokogiri/xml_xpath.h +0 -11
  288. data/ext/nokogiri/zlib1.dll +0 -0
  289. data/lib/action-nokogiri.rb +0 -30
  290. data/lib/nokogiri/css/generated_parser.rb +0 -713
  291. data/lib/nokogiri/css/generated_tokenizer.rb +0 -144
  292. data/lib/nokogiri/decorators.rb +0 -2
  293. data/lib/nokogiri/decorators/hpricot.rb +0 -3
  294. data/lib/nokogiri/decorators/hpricot/node.rb +0 -56
  295. data/lib/nokogiri/decorators/hpricot/node_set.rb +0 -54
  296. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +0 -28
  297. data/lib/nokogiri/hpricot.rb +0 -51
  298. data/lib/nokogiri/xml/comment.rb +0 -6
  299. data/lib/nokogiri/xml/element.rb +0 -6
  300. data/lib/nokogiri/xml/entity_declaration.rb +0 -9
  301. data/lib/nokogiri/xml/fragment_handler.rb +0 -34
  302. data/test/hpricot/files/basic.xhtml +0 -17
  303. data/test/hpricot/files/boingboing.html +0 -2266
  304. data/test/hpricot/files/cy0.html +0 -3653
  305. data/test/hpricot/files/immob.html +0 -400
  306. data/test/hpricot/files/pace_application.html +0 -1320
  307. data/test/hpricot/files/tenderlove.html +0 -16
  308. data/test/hpricot/files/uswebgen.html +0 -220
  309. data/test/hpricot/files/utf8.html +0 -1054
  310. data/test/hpricot/files/week9.html +0 -1723
  311. data/test/hpricot/files/why.xml +0 -19
  312. data/test/hpricot/load_files.rb +0 -11
  313. data/test/hpricot/test_alter.rb +0 -68
  314. data/test/hpricot/test_builder.rb +0 -20
  315. data/test/hpricot/test_parser.rb +0 -426
  316. data/test/hpricot/test_paths.rb +0 -15
  317. data/test/hpricot/test_preserved.rb +0 -77
  318. data/test/hpricot/test_xml.rb +0 -30
  319. data/test/test_gc.rb +0 -15
@@ -1,6 +1,8 @@
1
1
  module Nokogiri
2
2
  module XML
3
- class CDATA < Text
3
+ class CDATA < Nokogiri::XML::Text
4
+ ###
5
+ # Get the name of this CDATA node
4
6
  def name
5
7
  '#cdata-section'
6
8
  end
@@ -0,0 +1,7 @@
1
+ module Nokogiri
2
+ module XML
3
+ class CharacterData < Nokogiri::XML::Node
4
+ include Nokogiri::XML::PP::CharacterData
5
+ end
6
+ end
7
+ end
@@ -1,16 +1,86 @@
1
1
  module Nokogiri
2
2
  module XML
3
- ####
3
+ ##
4
4
  # Nokogiri::XML::Document is the main entry point for dealing with
5
5
  # XML documents. The Document is created by parsing an XML document.
6
6
  # See Nokogiri.XML()
7
7
  #
8
8
  # For searching a Document, see Nokogiri::XML::Node#css and
9
9
  # Nokogiri::XML::Node#xpath
10
- class Document < Node
10
+ class Document < Nokogiri::XML::Node
11
+ ##
12
+ # Parse an XML file. +thing+ may be a String, or any object that
13
+ # responds to _read_ and _close_ such as an IO, or StringIO.
14
+ # +url+ is resource where this document is located. +encoding+ is the
15
+ # encoding that should be used when processing the document. +options+
16
+ # is a number that sets options in the parser, such as
17
+ # Nokogiri::XML::ParseOptions::RECOVER. See the constants in
18
+ # Nokogiri::XML::ParseOptions.
19
+ def self.parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML, &block
20
+
21
+ options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
22
+ # Give the options to the user
23
+ yield options if block_given?
24
+
25
+ if string_or_io.respond_to?(:read)
26
+ url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
27
+ return read_io(string_or_io, url, encoding, options.to_i)
28
+ end
29
+
30
+ # read_memory pukes on empty docs
31
+ return new if string_or_io.nil? or string_or_io.empty?
32
+
33
+ read_memory(string_or_io, url, encoding, options.to_i)
34
+ end
35
+
11
36
  # A list of Nokogiri::XML::SyntaxError found when parsing a document
12
37
  attr_accessor :errors
13
38
 
39
+ def initialize *args # :nodoc:
40
+ @errors = []
41
+ @decorators = nil
42
+ end
43
+
44
+ ##
45
+ # Create an element with +name+, and optionally setting the content and attributes.
46
+ #
47
+ # doc.create_element "div" # <div></div>
48
+ # doc.create_element "div", :class => "container" # <div class='container'></div>
49
+ # doc.create_element "div", "contents" # <div>contents</div>
50
+ # doc.create_element "div", "contents", :class => "container" # <div class='container'>contents</div>
51
+ # doc.create_element "div" { |node| node['class'] = "container" } # <div class='container'></div>
52
+ #
53
+ def create_element name, *args, &block
54
+ elm = Nokogiri::XML::Element.new(name, self, &block)
55
+ args.each do |arg|
56
+ case arg
57
+ when Hash
58
+ arg.each { |k,v|
59
+ key = k.to_s
60
+ if key =~ /^xmlns(:\w+)?$/
61
+ ns_name = key.split(":", 2)[1]
62
+ elm.add_namespace_definition ns_name, v
63
+ next
64
+ end
65
+ elm[k.to_s] = v.to_s
66
+ }
67
+ else
68
+ elm.content = arg
69
+ end
70
+ end
71
+ elm
72
+ end
73
+
74
+ # Create a text node with +text+
75
+ def create_text_node text, &block
76
+ Nokogiri::XML::Text.new(text.to_s, self, &block)
77
+ end
78
+
79
+ # Create a CDATA element containing +text+
80
+ def create_cdata text
81
+ Nokogiri::XML::CDATA.new(self, text.to_s)
82
+ end
83
+
14
84
  # The name of this document. Always returns "document"
15
85
  def name
16
86
  'document'
@@ -21,14 +91,71 @@ module Nokogiri
21
91
  self
22
92
  end
23
93
 
94
+ ##
95
+ # Recursively get all namespaces from this node and its subtree and
96
+ # return them as a hash.
97
+ #
98
+ # For example, given this document:
99
+ #
100
+ # <root xmlns:foo="bar">
101
+ # <bar xmlns:hello="world" />
102
+ # </root>
103
+ #
104
+ # This method will return:
105
+ #
106
+ # { 'xmlns:foo' => 'bar', 'xmlns:hello' => 'world' }
107
+ #
108
+ # WARNING: this method will clobber duplicate names in the keys.
109
+ # For example, given this document:
110
+ #
111
+ # <root xmlns:foo="bar">
112
+ # <bar xmlns:foo="baz" />
113
+ # </root>
114
+ #
115
+ # The hash returned will look like this: { 'xmlns:foo' => 'bar' }
116
+ #
117
+ # Non-prefixed default namespaces (as in "xmlns=") are not included
118
+ # in the hash.
119
+ #
120
+ # Note this is a very expensive operation in current implementation, as it
121
+ # traverses the entire graph, and also has to bring each node accross the
122
+ # libxml bridge into a ruby object.
123
+ def collect_namespaces
124
+ ns = {}
125
+ traverse { |j| ns.merge!(j.namespaces) }
126
+ ns
127
+ end
128
+
24
129
  # Get the list of decorators given +key+
25
- def decorators(key)
130
+ def decorators key
26
131
  @decorators ||= Hash.new
27
132
  @decorators[key] ||= []
28
133
  end
29
134
 
30
- ###
31
- # Explore a document with shortcut methods.
135
+ ##
136
+ # Validate this Document against it's DTD. Returns a list of errors on
137
+ # the document or +nil+ when there is no DTD.
138
+ def validate
139
+ return nil unless internal_subset
140
+ internal_subset.validate self
141
+ end
142
+
143
+ ##
144
+ # Explore a document with shortcut methods. See Nokogiri::Slop for details.
145
+ #
146
+ # Note that any nodes that have been instantiated before #slop!
147
+ # is called will not be decorated with sloppy behavior. So, if you're in
148
+ # irb, the preferred idiom is:
149
+ #
150
+ # irb> doc = Nokogiri::Slop my_markup
151
+ #
152
+ # and not
153
+ #
154
+ # irb> doc = Nokogiri::HTML my_markup
155
+ # ... followed by irb's implicit inspect (and therefore instantiation of every node) ...
156
+ # irb> doc.slop!
157
+ # ... which does absolutely nothing.
158
+ #
32
159
  def slop!
33
160
  unless decorators(XML::Node).include? Nokogiri::Decorators::Slop
34
161
  decorators(XML::Node) << Nokogiri::Decorators::Slop
@@ -38,9 +165,9 @@ module Nokogiri
38
165
  self
39
166
  end
40
167
 
41
- ###
168
+ ##
42
169
  # Apply any decorators to +node+
43
- def decorate(node)
170
+ def decorate node
44
171
  return unless @decorators
45
172
  @decorators.each { |klass,list|
46
173
  next unless node.is_a?(klass)
@@ -48,19 +175,44 @@ module Nokogiri
48
175
  }
49
176
  end
50
177
 
51
- def node_cache # :nodoc:
52
- @node_cache ||= {}
53
- end
54
-
55
178
  alias :to_xml :serialize
56
- alias :inner_html :serialize
179
+ alias :clone :dup
57
180
 
58
181
  # Get the hash of namespaces on the root Nokogiri::XML::Node
59
182
  def namespaces
60
- root ? root.collect_namespaces : {}
183
+ root ? root.namespaces : {}
184
+ end
185
+
186
+ ##
187
+ # Create a Nokogiri::XML::DocumentFragment from +tags+
188
+ # Returns an empty fragment if +tags+ is nil.
189
+ def fragment tags = nil
190
+ DocumentFragment.new(self, tags, self.root)
61
191
  end
62
192
 
63
- undef_method :swap, :parent, :namespace
193
+ undef_method :swap, :parent, :namespace, :default_namespace=
194
+ undef_method :add_namespace_definition, :attributes
195
+ undef_method :namespace_definitions, :line, :add_namespace
196
+
197
+ def add_child child
198
+ raise "Document already has a root node" if root
199
+ if child.type == Node::DOCUMENT_FRAG_NODE
200
+ raise "Document cannot have multiple root nodes" if child.children.size > 1
201
+ super(child.children.first)
202
+ else
203
+ super
204
+ end
205
+ end
206
+ alias :<< :add_child
207
+
208
+ private
209
+ def implied_xpath_context
210
+ "/"
211
+ end
212
+
213
+ def inspect_attributes
214
+ [:name, :children]
215
+ end
64
216
  end
65
217
  end
66
218
  end
@@ -1,9 +1,84 @@
1
1
  module Nokogiri
2
2
  module XML
3
- class DocumentFragment < Node
3
+ class DocumentFragment < Nokogiri::XML::Node
4
+ ##
5
+ # Create a new DocumentFragment from +tags+.
6
+ #
7
+ # If +ctx+ is present, it is used as a context node for the
8
+ # subtree created, e.g., namespaces will be resolved relative
9
+ # to +ctx+.
10
+ def initialize document, tags = nil, ctx = nil
11
+ return self unless tags
12
+
13
+ children = if ctx
14
+ ctx.parse(tags)
15
+ else
16
+ XML::Document.parse("<root>#{tags}</root>") \
17
+ .xpath("/root/node()")
18
+ end
19
+ children.each { |child| child.parent = self }
20
+ end
21
+
22
+ ###
23
+ # return the name for DocumentFragment
4
24
  def name
5
25
  '#document-fragment'
6
26
  end
27
+
28
+ ###
29
+ # Convert this DocumentFragment to a string
30
+ def to_s
31
+ children.to_s
32
+ end
33
+
34
+ ###
35
+ # Convert this DocumentFragment to html
36
+ # See Nokogiri::XML::NodeSet#to_html
37
+ def to_html *args
38
+ children.to_html(*args)
39
+ end
40
+
41
+ ###
42
+ # Convert this DocumentFragment to xhtml
43
+ # See Nokogiri::XML::NodeSet#to_xhtml
44
+ def to_xhtml *args
45
+ children.to_xhtml(*args)
46
+ end
47
+
48
+ ###
49
+ # Convert this DocumentFragment to xml
50
+ # See Nokogiri::XML::NodeSet#to_xml
51
+ def to_xml *args
52
+ children.to_xml(*args)
53
+ end
54
+
55
+ ###
56
+ # Search this fragment. See Nokogiri::XML::Node#css
57
+ def css *args
58
+ if children.any?
59
+ children.css(*args)
60
+ else
61
+ NodeSet.new(document)
62
+ end
63
+ end
64
+
65
+ alias :serialize :to_s
66
+
67
+ class << self
68
+ ####
69
+ # Create a Nokogiri::XML::DocumentFragment from +tags+
70
+ def parse tags
71
+ self.new(XML::Document.new, tags)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def coerce data
78
+ return super unless String === data
79
+
80
+ document.fragment(data).children
81
+ end
7
82
  end
8
83
  end
9
84
  end
@@ -1,8 +1,21 @@
1
1
  module Nokogiri
2
2
  module XML
3
- class DTD < Node
4
- def attributes
5
- nil
3
+ class DTD < Nokogiri::XML::Node
4
+ undef_method :attribute_nodes
5
+ undef_method :values
6
+ undef_method :content
7
+ undef_method :namespace
8
+ undef_method :namespace_definitions
9
+ undef_method :line
10
+
11
+ def keys
12
+ attributes.keys
13
+ end
14
+
15
+ def each &block
16
+ attributes.each { |key, value|
17
+ block.call([key, value])
18
+ }
6
19
  end
7
20
  end
8
21
  end
@@ -0,0 +1,36 @@
1
+ module Nokogiri
2
+ module XML
3
+ ###
4
+ # Represents the allowed content in an Element Declaration inside a DTD:
5
+ #
6
+ # <?xml version="1.0"?><?TEST-STYLE PIDATA?>
7
+ # <!DOCTYPE staff SYSTEM "staff.dtd" [
8
+ # <!ELEMENT div1 (head, (p | list | note)*, div2*)>
9
+ # ]>
10
+ # </root>
11
+ #
12
+ # ElementContent represents the tree inside the <!ELEMENT> tag shown above
13
+ # that lists the possible content for the div1 tag.
14
+ class ElementContent
15
+ # Possible definitions of type
16
+ PCDATA = 1
17
+ ELEMENT = 2
18
+ SEQ = 3
19
+ OR = 4
20
+
21
+ # Possible content occurrences
22
+ ONCE = 1
23
+ OPT = 2
24
+ MULT = 3
25
+ PLUS = 4
26
+
27
+ attr_reader :document
28
+
29
+ ###
30
+ # Get the children of this ElementContent node
31
+ def children
32
+ [c1, c2].compact
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Nokogiri
2
+ module XML
3
+ class ElementDecl < Nokogiri::XML::Node
4
+ undef_method :namespace
5
+ undef_method :namespace_definitions
6
+ undef_method :line
7
+
8
+ def inspect
9
+ "#<#{self.class.name}:#{sprintf("0x%x", object_id)} #{to_s.inspect}>"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Nokogiri
2
+ module XML
3
+ class EntityDecl < Nokogiri::XML::Node
4
+ undef_method :attribute_nodes
5
+ undef_method :attributes
6
+ undef_method :namespace
7
+ undef_method :namespace_definitions
8
+ undef_method :line
9
+
10
+ def self.new name, doc, *args
11
+ doc.create_entity(name, *args)
12
+ end
13
+
14
+ def inspect
15
+ "#<#{self.class.name}:#{sprintf("0x%x", object_id)} #{to_s.inspect}>"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Nokogiri
2
+ module XML
3
+ class Namespace
4
+ include Nokogiri::XML::PP::Node
5
+ attr_reader :document
6
+
7
+ private
8
+ def inspect_attributes
9
+ [:prefix, :href]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -34,35 +34,60 @@ module Nokogiri
34
34
  #
35
35
  # You may search this node's subtree using Node#xpath and Node#css
36
36
  class Node
37
+ include Nokogiri::XML::PP::Node
38
+ include Enumerable
39
+
40
+ # Element node type, see Nokogiri::XML::Node#element?
37
41
  ELEMENT_NODE = 1
42
+ # Attribute node type
38
43
  ATTRIBUTE_NODE = 2
44
+ # Text node type, see Nokogiri::XML::Node#text?
39
45
  TEXT_NODE = 3
46
+ # CDATA node type, see Nokogiri::XML::Node#cdata?
40
47
  CDATA_SECTION_NODE = 4
48
+ # Entity reference node type
41
49
  ENTITY_REF_NODE = 5
50
+ # Entity node type
42
51
  ENTITY_NODE = 6
52
+ # PI node type
43
53
  PI_NODE = 7
54
+ # Comment node type, see Nokogiri::XML::Node#comment?
44
55
  COMMENT_NODE = 8
56
+ # Document node type, see Nokogiri::XML::Node#xml?
45
57
  DOCUMENT_NODE = 9
58
+ # Document type node type
46
59
  DOCUMENT_TYPE_NODE = 10
60
+ # Document fragment node type
47
61
  DOCUMENT_FRAG_NODE = 11
62
+ # Notation node type
48
63
  NOTATION_NODE = 12
64
+ # HTML document node type, see Nokogiri::XML::Node#html?
49
65
  HTML_DOCUMENT_NODE = 13
66
+ # DTD node type
50
67
  DTD_NODE = 14
68
+ # Element declaration type
51
69
  ELEMENT_DECL = 15
70
+ # Attribute declaration type
52
71
  ATTRIBUTE_DECL = 16
72
+ # Entity declaration type
53
73
  ENTITY_DECL = 17
74
+ # Namespace declaration type
54
75
  NAMESPACE_DECL = 18
76
+ # XInclude start type
55
77
  XINCLUDE_START = 19
78
+ # XInclude end type
56
79
  XINCLUDE_END = 20
80
+ # DOCB document node type
57
81
  DOCB_DOCUMENT_NODE = 21
58
82
 
59
- # The Document associated with this Node.
60
- attr_accessor :document
83
+ def initialize name, document # :nodoc:
84
+ # ... Ya. This is empty on purpose.
85
+ end
61
86
 
62
87
  ###
63
88
  # Decorate this node with the decorators set up in this node's Document
64
89
  def decorate!
65
- document.decorate(self) if document
90
+ document.decorate(self)
66
91
  end
67
92
 
68
93
  ###
@@ -70,13 +95,17 @@ module Nokogiri
70
95
  # optional hash of namespaces may be appended.
71
96
  # See Node#xpath and Node#css.
72
97
  def search *paths
98
+ # TODO use paths, handler, ns, binds = extract_params(paths)
73
99
  ns = paths.last.is_a?(Hash) ? paths.pop :
74
100
  (document.root ? document.root.namespaces : {})
101
+
102
+ prefix = "#{implied_xpath_context}/"
103
+
75
104
  xpath(*(paths.map { |path|
76
105
  path = path.to_s
77
- path =~ /^(\.\/|\/)/ ? path : CSS.xpath_for(
106
+ path =~ /^(\.\/|\/|\.\.)/ ? path : CSS.xpath_for(
78
107
  path,
79
- :prefix => ".//",
108
+ :prefix => prefix,
80
109
  :ns => ns
81
110
  )
82
111
  }.flatten.uniq) + [ns])
@@ -84,16 +113,28 @@ module Nokogiri
84
113
  alias :/ :search
85
114
 
86
115
  ###
116
+ # call-seq: xpath *paths, [namespace-bindings, variable-bindings, custom-handler-class]
117
+ #
87
118
  # Search this node for XPath +paths+. +paths+ must be one or more XPath
88
- # queries. A hash of namespaces may be appended. For example:
119
+ # queries.
89
120
  #
90
121
  # node.xpath('.//title')
91
- # node.xpath('.//foo:name', { 'foo' => 'http://example.org/' })
122
+ #
123
+ # A hash of namespace bindings may be appended. For example:
124
+ #
125
+ # node.xpath('.//foo:name', {'foo' => 'http://example.org/'})
92
126
  # node.xpath('.//xmlns:name', node.root.namespaces)
93
127
  #
94
- # Custom XPath functions may also be defined. To define custom functions
95
- # create a class and implement the # function you want to define.
96
- # For example:
128
+ # A hash of variable bindings may also be appended to the namespace bindings. For example:
129
+ #
130
+ # node.xpath('.//address[@domestic=$value]', nil, {:value => 'Yes'})
131
+ #
132
+ # Custom XPath functions may also be defined. To define custom
133
+ # functions create a class and implement the function you want
134
+ # to define. The first argument to the method will be the
135
+ # current matching NodeSet. Any other arguments are ones that
136
+ # you pass in. Note that this class may appear anywhere in the
137
+ # argument list. For example:
97
138
  #
98
139
  # node.xpath('.//title[regex(., "\w+")]', Class.new {
99
140
  # def regex node_set, regex
@@ -102,28 +143,23 @@ module Nokogiri
102
143
  # }.new)
103
144
  #
104
145
  def xpath *paths
105
- # Pop off our custom function handler if it exists
106
- handler = ![
107
- Hash, String, Symbol
108
- ].include?(paths.last.class) ? paths.pop : nil
109
-
110
- ns = paths.last.is_a?(Hash) ? paths.pop :
111
- (document.root ? document.root.namespaces : {})
112
-
113
146
  return NodeSet.new(document) unless document
114
147
 
148
+ paths, handler, ns, binds = extract_params(paths)
149
+
115
150
  sets = paths.map { |path|
116
151
  ctx = XPathContext.new(self)
117
152
  ctx.register_namespaces(ns)
118
- set = ctx.evaluate(path, handler).node_set
119
- set.document = document
120
- document.decorate(set)
121
- set
153
+
154
+ binds.each do |key,value|
155
+ ctx.register_variable key.to_s, value
156
+ end if binds
157
+
158
+ ctx.evaluate(path, handler)
122
159
  }
123
160
  return sets.first if sets.length == 1
124
161
 
125
162
  NodeSet.new(document) do |combined|
126
- document.decorate(combined)
127
163
  sets.each do |set|
128
164
  set.each do |node|
129
165
  combined << node
@@ -133,47 +169,83 @@ module Nokogiri
133
169
  end
134
170
 
135
171
  ###
172
+ # call-seq: css *rules, [namespace-bindings, custom-pseudo-class]
173
+ #
136
174
  # Search this node for CSS +rules+. +rules+ must be one or more CSS
137
- # selectors. For example:
175
+ # selectors. For example:
138
176
  #
139
177
  # node.css('title')
140
178
  # node.css('body h1.bold')
141
179
  # node.css('div + p.green', 'div#one')
142
180
  #
143
- # Custom CSS pseudo classes may also be defined. To define custom pseudo
144
- # classes, create a class and implement the custom pseudo class you
145
- # want defined. The first argument to the method will be the current
146
- # matching NodeSet. Any other arguments are ones that you pass in.
147
- # For example:
181
+ # A hash of namespace bindings may be appended. For example:
182
+ #
183
+ # node.css('bike|tire', {'bike' => 'http://schwinn.com/'})
184
+ #
185
+ # Custom CSS pseudo classes may also be defined. To define
186
+ # custom pseudo classes, create a class and implement the custom
187
+ # pseudo class you want defined. The first argument to the
188
+ # method will be the current matching NodeSet. Any other
189
+ # arguments are ones that you pass in. For example:
148
190
  #
149
191
  # node.css('title:regex("\w+")', Class.new {
150
192
  # def regex node_set, regex
151
193
  # node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
152
194
  # end
153
- # })
195
+ # }.new)
196
+ #
197
+ # Note that the CSS query string is case-sensitive with regards
198
+ # to your document type. That is, if you're looking for "H1" in
199
+ # an HTML document, you'll never find anything, since HTML tags
200
+ # will match only lowercase CSS queries. However, "H1" might be
201
+ # found in an XML document, where tags names are case-sensitive
202
+ # (e.g., "H1" is distinct from "h1").
154
203
  #
155
204
  def css *rules
156
- # Pop off our custom function handler if it exists
157
- handler = ![
158
- Hash, String, Symbol
159
- ].include?(rules.last.class) ? rules.pop : nil
205
+ rules, handler, ns, binds = extract_params(rules)
160
206
 
161
- ns = rules.last.is_a?(Hash) ? rules.pop :
162
- (document.root ? document.root.namespaces : {})
207
+ prefix = "#{implied_xpath_context}/"
163
208
 
164
209
  rules = rules.map { |rule|
165
- CSS.xpath_for(rule, :prefix => ".//", :ns => ns)
166
- }.flatten.uniq + [ns, handler].compact
210
+ CSS.xpath_for(rule, :prefix => prefix, :ns => ns)
211
+ }.flatten.uniq + [ns, handler, binds].compact
167
212
 
168
213
  xpath(*rules)
169
214
  end
170
215
 
216
+ ###
217
+ # Search this node's immediate children using CSS selector +selector+
218
+ def > selector
219
+ ns = document.root.namespaces
220
+ xpath CSS.xpath_for(selector, :prefix => "./", :ns => ns).first
221
+ end
222
+
171
223
  ###
172
224
  # Search for the first occurrence of +path+.
225
+ #
173
226
  # Returns nil if nothing is found, otherwise a Node.
174
227
  def at path, ns = document.root ? document.root.namespaces : {}
175
228
  search(path, ns).first
176
229
  end
230
+ alias :% :at
231
+
232
+ ##
233
+ # Search this node for the first occurrence of XPath +paths+.
234
+ # Equivalent to <tt>xpath(paths).first</tt>
235
+ # See Node#xpath for more information.
236
+ #
237
+ def at_xpath *paths
238
+ xpath(*paths).first
239
+ end
240
+
241
+ ##
242
+ # Search this node for the first occurrence of CSS +rules+.
243
+ # Equivalent to <tt>css(rules).first</tt>
244
+ # See Node#css for more information.
245
+ #
246
+ def at_css *rules
247
+ css(*rules).first
248
+ end
177
249
 
178
250
  ###
179
251
  # Get the attribute value for the attribute +name+
@@ -182,10 +254,172 @@ module Nokogiri
182
254
  get(name.to_s)
183
255
  end
184
256
 
257
+ ###
258
+ # Add +node_or_tags+ as a child of this Node.
259
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
260
+ #
261
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
262
+ def add_child node_or_tags
263
+ node_or_tags = coerce(node_or_tags)
264
+ if node_or_tags.is_a?(XML::NodeSet)
265
+ node_or_tags.each { |n| add_child_node n }
266
+ else
267
+ add_child_node node_or_tags
268
+ end
269
+ node_or_tags
270
+ end
271
+
272
+ ###
273
+ # Insert +node_or_tags+ before this Node (as a sibling).
274
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
275
+ #
276
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
277
+ #
278
+ # Also see related method +before+.
279
+ def add_previous_sibling node_or_tags
280
+ node_or_tags = coerce(node_or_tags)
281
+ if node_or_tags.is_a?(XML::NodeSet)
282
+ if text?
283
+ pivot = Nokogiri::XML::Node.new 'dummy', document
284
+ add_previous_sibling_node pivot
285
+ else
286
+ pivot = self
287
+ end
288
+ node_or_tags.each { |n| pivot.send :add_previous_sibling_node, n }
289
+ pivot.unlink if text?
290
+ else
291
+ add_previous_sibling_node node_or_tags
292
+ end
293
+ node_or_tags
294
+ end
295
+
296
+ ###
297
+ # Insert +node_or_tags+ after this Node (as a sibling).
298
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
299
+ #
300
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
301
+ #
302
+ # Also see related method +after+.
303
+ def add_next_sibling node_or_tags
304
+ node_or_tags = coerce(node_or_tags)
305
+ if node_or_tags.is_a?(XML::NodeSet)
306
+ if text?
307
+ pivot = Nokogiri::XML::Node.new 'dummy', document
308
+ add_next_sibling_node pivot
309
+ else
310
+ pivot = self
311
+ end
312
+ node_or_tags.reverse.each { |n| pivot.send :add_next_sibling_node, n }
313
+ pivot.unlink if text?
314
+ else
315
+ add_next_sibling_node node_or_tags
316
+ end
317
+ node_or_tags
318
+ end
319
+
320
+ ####
321
+ # Insert +node_or_tags+ before this node (as a sibling).
322
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
323
+ #
324
+ # Returns self, to support chaining of calls.
325
+ #
326
+ # Also see related method +add_previous_sibling+.
327
+ def before node_or_tags
328
+ add_previous_sibling node_or_tags
329
+ self
330
+ end
331
+
332
+ ####
333
+ # Insert +node_or_tags+ after this node (as a sibling).
334
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
335
+ #
336
+ # Returns self, to support chaining of calls.
337
+ #
338
+ # Also see related method +add_next_sibling+.
339
+ def after node_or_tags
340
+ add_next_sibling node_or_tags
341
+ self
342
+ end
343
+
344
+ ####
345
+ # Set the inner html for this Node to +node_or_tags+
346
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
347
+ #
348
+ # Returns self.
349
+ #
350
+ # Also see related method +children=+
351
+ def inner_html= node_or_tags
352
+ self.children = node_or_tags
353
+ self
354
+ end
355
+
356
+ ####
357
+ # Set the inner html for this Node +node_or_tags+
358
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
359
+ #
360
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
361
+ #
362
+ # Also see related method +inner_html=+
363
+ def children= node_or_tags
364
+ node_or_tags = coerce(node_or_tags)
365
+ children.unlink
366
+ if node_or_tags.is_a?(XML::NodeSet)
367
+ node_or_tags.each { |n| add_child_node n }
368
+ else
369
+ add_child node_or_tags
370
+ end
371
+ node_or_tags
372
+ end
373
+
374
+ ####
375
+ # Replace this Node with +node_or_tags+.
376
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
377
+ #
378
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
379
+ #
380
+ # Also see related method +swap+.
381
+ def replace node_or_tags
382
+ node_or_tags = coerce(node_or_tags)
383
+ if node_or_tags.is_a?(XML::NodeSet)
384
+ if text?
385
+ replacee = Nokogiri::XML::Node.new 'dummy', document
386
+ add_previous_sibling_node replacee
387
+ unlink
388
+ else
389
+ replacee = self
390
+ end
391
+ node_or_tags.each { |n| replacee.add_previous_sibling n }
392
+ replacee.unlink
393
+ else
394
+ replace_node node_or_tags
395
+ end
396
+ node_or_tags
397
+ end
398
+
399
+ ####
400
+ # Swap this Node for +node_or_tags+
401
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
402
+ #
403
+ # Returns self, to support chaining of calls.
404
+ #
405
+ # Also see related method +replace+.
406
+ def swap node_or_tags
407
+ replace node_or_tags
408
+ self
409
+ end
410
+
185
411
  alias :next :next_sibling
186
412
  alias :previous :previous_sibling
413
+
414
+ # :stopdoc:
415
+ # HACK: This is to work around an RDoc bug
416
+ alias :next= :add_next_sibling
417
+ # :startdoc:
418
+
419
+ alias :previous= :add_previous_sibling
187
420
  alias :remove :unlink
188
421
  alias :get_attribute :[]
422
+ alias :attr :[]
189
423
  alias :set_attribute :[]=
190
424
  alias :text :content
191
425
  alias :inner_text :content
@@ -195,10 +429,15 @@ module Nokogiri
195
429
  alias :name= :node_name=
196
430
  alias :type :node_type
197
431
  alias :to_str :text
432
+ alias :clone :dup
433
+ alias :elements :element_children
198
434
 
199
435
  ####
200
- # Returns a hash containing the node's attributes. The key is the
201
- # attribute name, the value is the string value of the attribute.
436
+ # Returns a hash containing the node's attributes. The key is
437
+ # the attribute name without any namespace, the value is a Nokogiri::XML::Attr
438
+ # representing the attribute.
439
+ # If you need to distinguish attributes with the same name, with different namespaces
440
+ # use #attribute_nodes instead.
202
441
  def attributes
203
442
  Hash[*(attribute_nodes.map { |node|
204
443
  [node.node_name, node]
@@ -221,7 +460,7 @@ module Nokogiri
221
460
  # Iterate over each attribute name and value pair for this Node.
222
461
  def each &block
223
462
  attribute_nodes.each { |node|
224
- block.call(node.node_name, node.value)
463
+ block.call([node.node_name, node.value])
225
464
  }
226
465
  end
227
466
 
@@ -232,62 +471,51 @@ module Nokogiri
232
471
  end
233
472
  alias :delete :remove_attribute
234
473
 
235
- ####
236
- # Create nodes from +data+ and insert them before this node
237
- # (as a sibling).
238
- def before data
239
- fragment(data).children.each do |node|
240
- add_previous_sibling node
241
- end
242
- self
243
- end
244
-
245
- ####
246
- # Create nodes from +data+ and insert them after this node
247
- # (as a sibling).
248
- def after data
249
- fragment(data).children.to_a.reverse.each do |node|
250
- add_next_sibling node
251
- end
252
- self
474
+ ###
475
+ # Returns true if this Node matches +selector+
476
+ def matches? selector
477
+ ancestors.last.search(selector).include?(self)
253
478
  end
254
479
 
255
- ####
256
- # Swap this Node for new nodes made from +data+
257
- def swap data
258
- before(data)
259
- remove
260
- self
480
+ ###
481
+ # Create a DocumentFragment containing +tags+ that is relative to _this_
482
+ # context node.
483
+ def fragment tags
484
+ type = document.html? ? Nokogiri::HTML : Nokogiri::XML
485
+ type::DocumentFragment.new(document, tags, self)
261
486
  end
262
487
 
263
- ####
264
- # Set the inner_html for this Node to +tags+
265
- def inner_html= tags
266
- children.each { |x| x.remove}
267
-
268
- fragment(tags).children.to_a.reverse.each do |node|
269
- add_child node
488
+ ###
489
+ # Parse +string_or_io+ as a document fragment within the context of
490
+ # *this* node. Returns a XML::NodeSet containing the nodes parsed from
491
+ # +string_or_io+.
492
+ def parse string_or_io, options = nil
493
+ options ||= (document.html? ? ParseOptions::DEFAULT_HTML : ParseOptions::DEFAULT_XML)
494
+ if Fixnum === options
495
+ options = Nokogiri::XML::ParseOptions.new(options)
270
496
  end
271
- self
272
- end
273
-
274
- ####
275
- # Create a Nokogiri::XML::DocumentFragment from +tags+
276
- def fragment tags
277
- classes = document.class.name.split('::')
278
- classes[-1] = 'SAX::Parser'
279
-
280
-
281
- fragment = DocumentFragment.new(self.document)
282
- parser = eval(classes.join('::')).new(
283
- FragmentHandler.new(fragment, tags)
284
- )
285
- parser.parse(tags)
286
- fragment
497
+ # Give the options to the user
498
+ yield options if block_given?
499
+
500
+ contents = string_or_io.respond_to?(:read) ?
501
+ string_or_io.read :
502
+ string_or_io
503
+
504
+ return Nokogiri::XML::NodeSet.new(document) if contents.empty?
505
+
506
+ ##
507
+ # This is a horrible hack, but I don't care. See #313 for background.
508
+ error_count = document.errors.length
509
+ node_set = in_context(contents, options.to_i)
510
+ if node_set.empty? and document.errors.length > error_count and options.recover?
511
+ fragment = Nokogiri::HTML::DocumentFragment.parse contents
512
+ node_set = fragment.children
513
+ end
514
+ node_set
287
515
  end
288
516
 
289
517
  ####
290
- # Set the content to +string+.
518
+ # Set the Node's content to a Text node containing +string+. The string gets XML escaped, not interpreted as markup.
291
519
  def content= string
292
520
  self.native_content = encode_special_chars(string.to_s)
293
521
  end
@@ -299,6 +527,33 @@ module Nokogiri
299
527
  parent_node
300
528
  end
301
529
 
530
+ ###
531
+ # Returns a Hash of {prefix => value} for all namespaces on this
532
+ # node and its ancestors.
533
+ #
534
+ # This method returns the same namespaces as #namespace_scopes.
535
+ #
536
+ # Returns namespaces in scope for self -- those defined on self
537
+ # element directly or any ancestor node -- as a Hash of
538
+ # attribute-name/value pairs. Note that the keys in this hash
539
+ # XML attributes that would be used to define this namespace,
540
+ # such as "xmlns:prefix", not just the prefix. Default namespace
541
+ # set on self will be included with key "xmlns". However,
542
+ # default namespaces set on ancestor will NOT be, even if self
543
+ # has no explicit default namespace.
544
+ def namespaces
545
+ Hash[*namespace_scopes.map { |nd|
546
+ key = ['xmlns', nd.prefix].compact.join(':')
547
+ if RUBY_VERSION >= '1.9' && document.encoding
548
+ begin
549
+ key.force_encoding document.encoding
550
+ rescue ArgumentError
551
+ end
552
+ end
553
+ [key, nd.href]
554
+ }.flatten]
555
+ end
556
+
302
557
  # Returns true if this is a Comment
303
558
  def comment?
304
559
  type == COMMENT_NODE
@@ -324,6 +579,21 @@ module Nokogiri
324
579
  type == TEXT_NODE
325
580
  end
326
581
 
582
+ # Returns true if this is a DocumentFragment
583
+ def fragment?
584
+ type == DOCUMENT_FRAG_NODE
585
+ end
586
+
587
+ ###
588
+ # Fetch the Nokogiri::HTML::ElementDescription for this node. Returns
589
+ # nil on XML documents and on unknown tags.
590
+ def description
591
+ return nil if document.xml?
592
+ Nokogiri::HTML::ElementDescription[name]
593
+ end
594
+
595
+ ###
596
+ # Is this a read only node?
327
597
  def read_only?
328
598
  # According to gdome2, these are read-only node types
329
599
  [NOTATION_NODE, ENTITY_NODE, ENTITY_DECL].include?(type)
@@ -335,12 +605,16 @@ module Nokogiri
335
605
  end
336
606
  alias :elem? :element?
337
607
 
608
+ ###
609
+ # Turn this node in to a string. If the document is HTML, this method
610
+ # returns html. If the document is XML, this method returns XML.
338
611
  def to_s
339
612
  document.xml? ? to_xml : to_html
340
613
  end
341
614
 
342
- def inner_html
343
- children.map { |x| x.to_html }.join
615
+ # Get the inner_html for this node's Node#children
616
+ def inner_html *args
617
+ children.map { |x| x.to_html(*args) }.join
344
618
  end
345
619
 
346
620
  # Get the path to this node as a CSS expression
@@ -350,44 +624,70 @@ module Nokogiri
350
624
  }.compact.join(' > ')
351
625
  end
352
626
 
353
- # recursively get all namespaces from this node and its subtree
354
- def collect_namespaces
355
- # TODO: print warning message if a prefix refers to more than one URI in the document?
356
- ns = {}
357
- traverse {|j| ns.merge!(j.namespaces)}
358
- ns
359
- end
360
-
361
627
  ###
362
- # Get a list of ancestor Node for this Node
363
- def ancestors
364
- return [] unless respond_to?(:parent)
628
+ # Get a list of ancestor Node for this Node. If +selector+ is given,
629
+ # the ancestors must match +selector+
630
+ def ancestors selector = nil
631
+ return NodeSet.new(document) unless respond_to?(:parent)
632
+ return NodeSet.new(document) unless parent
365
633
 
366
634
  parents = [parent]
367
635
 
368
636
  while parents.last.respond_to?(:parent)
369
- parents << parents.last.parent
637
+ break unless ctx_parent = parents.last.parent
638
+ parents << ctx_parent
370
639
  end
371
- parents
640
+
641
+ return NodeSet.new(document, parents) unless selector
642
+
643
+ root = parents.last
644
+
645
+ NodeSet.new(document, parents.find_all { |parent|
646
+ root.search(selector).include?(parent)
647
+ })
648
+ end
649
+
650
+ ###
651
+ # Adds a default namespace supplied as a string +url+ href, to self.
652
+ # The consequence is as an xmlns attribute with supplied argument were
653
+ # present in parsed XML. A default namespace set with this method will
654
+ # now show up in #attributes, but when this node is serialized to XML an
655
+ # "xmlns" attribute will appear. See also #namespace and #namespace=
656
+ def default_namespace= url
657
+ add_namespace_definition(nil, url)
658
+ end
659
+ alias :add_namespace :add_namespace_definition
660
+
661
+ ###
662
+ # Set the default namespace on this node (as would be defined with an
663
+ # "xmlns=" attribute in XML source), as a Namespace object +ns+. Note that
664
+ # a Namespace added this way will NOT be serialized as an xmlns attribute
665
+ # for this node. You probably want #default_namespace= instead, or perhaps
666
+ # #add_namespace_definition with a nil prefix argument.
667
+ def namespace= ns
668
+ return set_namespace(ns) unless ns
669
+
670
+ unless Nokogiri::XML::Namespace === ns
671
+ raise TypeError, "#{ns.class} can't be coerced into Nokogiri::XML::Namespace"
672
+ end
673
+ if ns.document != document
674
+ raise ArgumentError, 'namespace must be declared on the same document'
675
+ end
676
+
677
+ set_namespace ns
372
678
  end
373
679
 
374
680
  ####
375
681
  # Yields self and all children to +block+ recursively.
376
- def traverse(&block)
682
+ def traverse &block
377
683
  children.each{|j| j.traverse(&block) }
378
684
  block.call(self)
379
685
  end
380
686
 
381
- ####
382
- # replace node with the new node in the document.
383
- def replace(new_node)
384
- if new_node.is_a?(Document) || !new_node.is_a?(XML::Node)
385
- raise ArgumentError, <<-EOERR
386
- Node.replace requires a Node argument, and cannot accept a Document.
387
- (You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
388
- EOERR
389
- end
390
- replace_with_node new_node
687
+ ###
688
+ # Accept a visitor. This method calls "visit" on +visitor+ with self.
689
+ def accept visitor
690
+ visitor.visit(self)
391
691
  end
392
692
 
393
693
  ###
@@ -399,97 +699,192 @@ Node.replace requires a Node argument, and cannot accept a Document.
399
699
  end
400
700
 
401
701
  ###
402
- # Serialize Node using +encoding+ and +save_options+. Save options
403
- # can also be set using a block. See SaveOptions.
702
+ # Serialize Node using +options+. Save options can also be set using a
703
+ # block. See SaveOptions.
404
704
  #
405
705
  # These two statements are equivalent:
406
706
  #
407
- # node.serialize('UTF-8', FORMAT | AS_XML)
707
+ # node.serialize(:encoding => 'UTF-8', :save_with => FORMAT | AS_XML)
408
708
  #
409
709
  # or
410
710
  #
411
- # node.serialize('UTF-8') do |config|
711
+ # node.serialize(:encoding => 'UTF-8') do |config|
412
712
  # config.format.as_xml
413
713
  # end
414
714
  #
415
- def serialize encoding = nil, save_options = SaveOptions::FORMAT, &block
416
- io = StringIO.new
417
- write_to io, encoding, save_options, &block
418
- io.rewind
419
- io.read
715
+ def serialize *args, &block
716
+ options = args.first.is_a?(Hash) ? args.shift : {
717
+ :encoding => args[0],
718
+ :save_with => args[1] || SaveOptions::FORMAT
719
+ }
720
+
721
+ encoding = options[:encoding] || document.encoding
722
+
723
+ outstring = ""
724
+ if encoding && outstring.respond_to?(:force_encoding)
725
+ outstring.force_encoding(Encoding.find(encoding))
726
+ end
727
+ io = StringIO.new(outstring)
728
+ write_to io, options, &block
729
+ io.string
420
730
  end
421
731
 
422
732
  ###
423
- # Serialize this Node to HTML using +encoding+
424
- def to_html encoding = nil
733
+ # Serialize this Node to HTML
734
+ #
735
+ # doc.to_html
736
+ #
737
+ # See Node#write_to for a list of +options+. For formatted output,
738
+ # use Node#to_xhtml instead.
739
+ def to_html options = {}
425
740
  # FIXME: this is a hack around broken libxml versions
426
741
  return dump_html if %w[2 6] === LIBXML_VERSION.split('.')[0..1]
427
742
 
428
- serialize(encoding, SaveOptions::FORMAT |
429
- SaveOptions::NO_DECLARATION |
430
- SaveOptions::NO_EMPTY_TAGS |
431
- SaveOptions::AS_HTML)
743
+ options[:save_with] ||= SaveOptions::DEFAULT_HTML
744
+ serialize(options)
432
745
  end
433
746
 
434
747
  ###
435
- # Serialize this Node to XML using +encoding+
436
- def to_xml encoding = nil
437
- serialize(encoding, SaveOptions::FORMAT | SaveOptions::AS_XML)
748
+ # Serialize this Node to XML using +options+
749
+ #
750
+ # doc.to_xml(:indent => 5, :encoding => 'UTF-8')
751
+ #
752
+ # See Node#write_to for a list of +options+
753
+ def to_xml options = {}
754
+ options[:save_with] ||= SaveOptions::DEFAULT_XML
755
+ serialize(options)
438
756
  end
439
757
 
440
758
  ###
441
- # Serialize this Node to XML using +encoding+
442
- def to_xhtml encoding = nil
759
+ # Serialize this Node to XHTML using +options+
760
+ #
761
+ # doc.to_xhtml(:indent => 5, :encoding => 'UTF-8')
762
+ #
763
+ # See Node#write_to for a list of +options+
764
+ def to_xhtml options = {}
443
765
  # FIXME: this is a hack around broken libxml versions
444
766
  return dump_html if %w[2 6] === LIBXML_VERSION.split('.')[0..1]
445
767
 
446
- serialize(encoding, SaveOptions::FORMAT |
447
- SaveOptions::NO_DECLARATION |
448
- SaveOptions::NO_EMPTY_TAGS |
449
- SaveOptions::AS_XHTML)
768
+ options[:save_with] ||= SaveOptions::DEFAULT_XHTML
769
+ serialize(options)
450
770
  end
451
771
 
452
772
  ###
453
- # Write Node to +io+ with +encoding+ and +save_options+
454
- def write_to io, encoding = nil, save_options = SaveOptions::FORMAT
455
- config = SaveOptions.new(save_options)
773
+ # Write Node to +io+ with +options+. +options+ modify the output of
774
+ # this method. Valid options are:
775
+ #
776
+ # * +:encoding+ for changing the encoding
777
+ # * +:indent_text+ the indentation text, defaults to one space
778
+ # * +:indent+ the number of +:indent_text+ to use, defaults to 2
779
+ # * +:save_with+ a combination of SaveOptions constants.
780
+ #
781
+ # To save with UTF-8 indented twice:
782
+ #
783
+ # node.write_to(io, :encoding => 'UTF-8', :indent => 2)
784
+ #
785
+ # To save indented with two dashes:
786
+ #
787
+ # node.write_to(io, :indent_text => '-', :indent => 2
788
+ #
789
+ def write_to io, *options
790
+ options = options.first.is_a?(Hash) ? options.shift : {}
791
+ encoding = options[:encoding] || options[0]
792
+ save_options = options[:save_with] || options[1] || SaveOptions::FORMAT
793
+ indent_text = options[:indent_text] || ' '
794
+ indent_times = options[:indent] || 2
795
+
796
+
797
+ config = SaveOptions.new(save_options.to_i)
456
798
  yield config if block_given?
457
799
 
458
- native_write_to(io, encoding, config.options)
800
+ native_write_to(io, encoding, indent_text * indent_times, config.options)
801
+ end
802
+
803
+ ###
804
+ # Write Node as HTML to +io+ with +options+
805
+ #
806
+ # See Node#write_to for a list of +options+
807
+ def write_html_to io, options = {}
808
+ # FIXME: this is a hack around broken libxml versions
809
+ return (io << dump_html) if %w[2 6] === LIBXML_VERSION.split('.')[0..1]
810
+
811
+ options[:save_with] ||= SaveOptions::DEFAULT_HTML
812
+ write_to io, options
459
813
  end
460
814
 
461
815
  ###
462
- # Write Node as HTML to +io+ with +encoding+
463
- def write_html_to io, encoding = nil
464
- write_to io, encoding, SaveOptions::FORMAT |
465
- SaveOptions::NO_DECLARATION |
466
- SaveOptions::NO_EMPTY_TAGS |
467
- SaveOptions::AS_HTML
816
+ # Write Node as XHTML to +io+ with +options+
817
+ #
818
+ # See Node#write_to for a list of +options+
819
+ def write_xhtml_to io, options = {}
820
+ # FIXME: this is a hack around broken libxml versions
821
+ return (io << dump_html) if %w[2 6] === LIBXML_VERSION.split('.')[0..1]
822
+
823
+ options[:save_with] ||= SaveOptions::DEFAULT_XHTML
824
+ write_to io, options
468
825
  end
469
826
 
470
827
  ###
471
- # Write Node as XHTML to +io+ with +encoding+
472
- def write_xhtml_to io, encoding = nil
473
- write_to io, encoding, SaveOptions::FORMAT |
474
- SaveOptions::NO_DECLARATION |
475
- SaveOptions::NO_EMPTY_TAGS |
476
- SaveOptions::AS_XHTML
828
+ # Write Node as XML to +io+ with +options+
829
+ #
830
+ # doc.write_xml_to io, :encoding => 'UTF-8'
831
+ #
832
+ # See Node#write_to for a list of options
833
+ def write_xml_to io, options = {}
834
+ options[:save_with] ||= SaveOptions::DEFAULT_XML
835
+ write_to io, options
477
836
  end
478
837
 
479
838
  ###
480
- # Write Node as XML to +io+ with +encoding+
481
- def write_xml_to io, encoding = nil
482
- write_to io, encoding, SaveOptions::FORMAT | SaveOptions::AS_XML
839
+ # Compare two Node objects with respect to their Document. Nodes from
840
+ # different documents cannot be compared.
841
+ def <=> other
842
+ return nil unless other.is_a?(Nokogiri::XML::Node)
843
+ return nil unless document == other.document
844
+ compare other
483
845
  end
484
846
 
485
- # Create a new node from +string+
486
- #
487
- # THIS METHOD IS DEPRECATED
488
- # This method is deprecated and will be removed in 1.3.0 or by
489
- # March 1, 2009. Instead, use Nokogiri::XML::Node#fragment()
490
- def self.new_from_str string
491
- $stderr.puts("This method is deprecated and will be removed in 1.3.0 or by March 1, 2009. Instead, use Nokogiri::XML::Node#fragment")
492
- Nokogiri::HTML.fragment(string).first
847
+ private
848
+
849
+ def extract_params params # :nodoc:
850
+ # Pop off our custom function handler if it exists
851
+ handler = params.find { |param|
852
+ ![Hash, String, Symbol].include?(param.class)
853
+ }
854
+
855
+ params -= [handler] if handler
856
+
857
+ hashes = []
858
+ hashes << params.pop while Hash === params.last || params.last.nil?
859
+
860
+ ns, binds = hashes.reverse
861
+
862
+ ns ||= document.root ? document.root.namespaces : {}
863
+
864
+ [params, handler, ns, binds]
865
+ end
866
+
867
+ def coerce data # :nodoc:
868
+ return data if data.is_a?(XML::NodeSet)
869
+ return data.children if data.is_a?(XML::DocumentFragment)
870
+ return fragment(data).children if data.is_a?(String)
871
+
872
+ if data.is_a?(Document) || !data.is_a?(XML::Node)
873
+ raise ArgumentError, <<-EOERR
874
+ Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
875
+ (You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
876
+ EOERR
877
+ end
878
+
879
+ data
880
+ end
881
+
882
+ def implied_xpath_context
883
+ "./"
884
+ end
885
+
886
+ def inspect_attributes
887
+ [:name, :namespace, :attribute_nodes, :children]
493
888
  end
494
889
  end
495
890
  end