nokogiri 1.6.2.rc1-x64-mingw32

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 (263) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +26 -0
  3. data/.editorconfig +17 -0
  4. data/.gemtest +0 -0
  5. data/.travis.yml +25 -0
  6. data/CHANGELOG.ja.rdoc +857 -0
  7. data/CHANGELOG.rdoc +880 -0
  8. data/C_CODING_STYLE.rdoc +33 -0
  9. data/Gemfile +21 -0
  10. data/Manifest.txt +371 -0
  11. data/README.ja.rdoc +112 -0
  12. data/README.rdoc +180 -0
  13. data/ROADMAP.md +89 -0
  14. data/Rakefile +351 -0
  15. data/STANDARD_RESPONSES.md +47 -0
  16. data/Y_U_NO_GEMSPEC.md +155 -0
  17. data/bin/nokogiri +78 -0
  18. data/build_all +130 -0
  19. data/dependencies.yml +4 -0
  20. data/ext/nokogiri/depend +358 -0
  21. data/ext/nokogiri/extconf.rb +453 -0
  22. data/ext/nokogiri/html_document.c +170 -0
  23. data/ext/nokogiri/html_document.h +10 -0
  24. data/ext/nokogiri/html_element_description.c +279 -0
  25. data/ext/nokogiri/html_element_description.h +10 -0
  26. data/ext/nokogiri/html_entity_lookup.c +32 -0
  27. data/ext/nokogiri/html_entity_lookup.h +8 -0
  28. data/ext/nokogiri/html_sax_parser_context.c +116 -0
  29. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  30. data/ext/nokogiri/html_sax_push_parser.c +87 -0
  31. data/ext/nokogiri/html_sax_push_parser.h +9 -0
  32. data/ext/nokogiri/nokogiri.c +148 -0
  33. data/ext/nokogiri/nokogiri.h +164 -0
  34. data/ext/nokogiri/xml_attr.c +94 -0
  35. data/ext/nokogiri/xml_attr.h +9 -0
  36. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  37. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  38. data/ext/nokogiri/xml_cdata.c +56 -0
  39. data/ext/nokogiri/xml_cdata.h +9 -0
  40. data/ext/nokogiri/xml_comment.c +54 -0
  41. data/ext/nokogiri/xml_comment.h +9 -0
  42. data/ext/nokogiri/xml_document.c +577 -0
  43. data/ext/nokogiri/xml_document.h +23 -0
  44. data/ext/nokogiri/xml_document_fragment.c +48 -0
  45. data/ext/nokogiri/xml_document_fragment.h +10 -0
  46. data/ext/nokogiri/xml_dtd.c +202 -0
  47. data/ext/nokogiri/xml_dtd.h +10 -0
  48. data/ext/nokogiri/xml_element_content.c +123 -0
  49. data/ext/nokogiri/xml_element_content.h +10 -0
  50. data/ext/nokogiri/xml_element_decl.c +69 -0
  51. data/ext/nokogiri/xml_element_decl.h +9 -0
  52. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  53. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  54. data/ext/nokogiri/xml_entity_decl.c +110 -0
  55. data/ext/nokogiri/xml_entity_decl.h +10 -0
  56. data/ext/nokogiri/xml_entity_reference.c +52 -0
  57. data/ext/nokogiri/xml_entity_reference.h +9 -0
  58. data/ext/nokogiri/xml_io.c +56 -0
  59. data/ext/nokogiri/xml_io.h +11 -0
  60. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  61. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  62. data/ext/nokogiri/xml_namespace.c +78 -0
  63. data/ext/nokogiri/xml_namespace.h +13 -0
  64. data/ext/nokogiri/xml_node.c +1541 -0
  65. data/ext/nokogiri/xml_node.h +13 -0
  66. data/ext/nokogiri/xml_node_set.c +467 -0
  67. data/ext/nokogiri/xml_node_set.h +14 -0
  68. data/ext/nokogiri/xml_processing_instruction.c +56 -0
  69. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  70. data/ext/nokogiri/xml_reader.c +681 -0
  71. data/ext/nokogiri/xml_reader.h +10 -0
  72. data/ext/nokogiri/xml_relax_ng.c +161 -0
  73. data/ext/nokogiri/xml_relax_ng.h +9 -0
  74. data/ext/nokogiri/xml_sax_parser.c +312 -0
  75. data/ext/nokogiri/xml_sax_parser.h +39 -0
  76. data/ext/nokogiri/xml_sax_parser_context.c +262 -0
  77. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  78. data/ext/nokogiri/xml_sax_push_parser.c +115 -0
  79. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  80. data/ext/nokogiri/xml_schema.c +205 -0
  81. data/ext/nokogiri/xml_schema.h +9 -0
  82. data/ext/nokogiri/xml_syntax_error.c +63 -0
  83. data/ext/nokogiri/xml_syntax_error.h +13 -0
  84. data/ext/nokogiri/xml_text.c +52 -0
  85. data/ext/nokogiri/xml_text.h +9 -0
  86. data/ext/nokogiri/xml_xpath_context.c +307 -0
  87. data/ext/nokogiri/xml_xpath_context.h +10 -0
  88. data/ext/nokogiri/xslt_stylesheet.c +270 -0
  89. data/ext/nokogiri/xslt_stylesheet.h +14 -0
  90. data/lib/nokogiri.rb +137 -0
  91. data/lib/nokogiri/2.0/nokogiri.so +0 -0
  92. data/lib/nokogiri/2.1/nokogiri.so +0 -0
  93. data/lib/nokogiri/css.rb +27 -0
  94. data/lib/nokogiri/css/node.rb +52 -0
  95. data/lib/nokogiri/css/parser.rb +715 -0
  96. data/lib/nokogiri/css/parser.y +249 -0
  97. data/lib/nokogiri/css/parser_extras.rb +91 -0
  98. data/lib/nokogiri/css/syntax_error.rb +7 -0
  99. data/lib/nokogiri/css/tokenizer.rb +152 -0
  100. data/lib/nokogiri/css/tokenizer.rex +55 -0
  101. data/lib/nokogiri/css/xpath_visitor.rb +219 -0
  102. data/lib/nokogiri/decorators/slop.rb +35 -0
  103. data/lib/nokogiri/html.rb +37 -0
  104. data/lib/nokogiri/html/builder.rb +35 -0
  105. data/lib/nokogiri/html/document.rb +333 -0
  106. data/lib/nokogiri/html/document_fragment.rb +41 -0
  107. data/lib/nokogiri/html/element_description.rb +23 -0
  108. data/lib/nokogiri/html/element_description_defaults.rb +671 -0
  109. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  110. data/lib/nokogiri/html/sax/parser.rb +52 -0
  111. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  112. data/lib/nokogiri/html/sax/push_parser.rb +16 -0
  113. data/lib/nokogiri/syntax_error.rb +4 -0
  114. data/lib/nokogiri/version.rb +106 -0
  115. data/lib/nokogiri/xml.rb +73 -0
  116. data/lib/nokogiri/xml/attr.rb +14 -0
  117. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  118. data/lib/nokogiri/xml/builder.rb +443 -0
  119. data/lib/nokogiri/xml/cdata.rb +11 -0
  120. data/lib/nokogiri/xml/character_data.rb +7 -0
  121. data/lib/nokogiri/xml/document.rb +279 -0
  122. data/lib/nokogiri/xml/document_fragment.rb +112 -0
  123. data/lib/nokogiri/xml/dtd.rb +32 -0
  124. data/lib/nokogiri/xml/element_content.rb +36 -0
  125. data/lib/nokogiri/xml/element_decl.rb +13 -0
  126. data/lib/nokogiri/xml/entity_decl.rb +19 -0
  127. data/lib/nokogiri/xml/namespace.rb +13 -0
  128. data/lib/nokogiri/xml/node.rb +982 -0
  129. data/lib/nokogiri/xml/node/save_options.rb +61 -0
  130. data/lib/nokogiri/xml/node_set.rb +355 -0
  131. data/lib/nokogiri/xml/notation.rb +6 -0
  132. data/lib/nokogiri/xml/parse_options.rb +98 -0
  133. data/lib/nokogiri/xml/pp.rb +2 -0
  134. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  135. data/lib/nokogiri/xml/pp/node.rb +56 -0
  136. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  137. data/lib/nokogiri/xml/reader.rb +112 -0
  138. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  139. data/lib/nokogiri/xml/sax.rb +4 -0
  140. data/lib/nokogiri/xml/sax/document.rb +171 -0
  141. data/lib/nokogiri/xml/sax/parser.rb +123 -0
  142. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  143. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  144. data/lib/nokogiri/xml/schema.rb +63 -0
  145. data/lib/nokogiri/xml/syntax_error.rb +47 -0
  146. data/lib/nokogiri/xml/text.rb +9 -0
  147. data/lib/nokogiri/xml/xpath.rb +10 -0
  148. data/lib/nokogiri/xml/xpath/syntax_error.rb +11 -0
  149. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  150. data/lib/nokogiri/xslt.rb +56 -0
  151. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  152. data/lib/xsd/xmlparser/nokogiri.rb +102 -0
  153. data/suppressions/README.txt +1 -0
  154. data/suppressions/nokogiri_ree-1.8.7.358.supp +61 -0
  155. data/suppressions/nokogiri_ruby-1.8.7.370.supp +0 -0
  156. data/suppressions/nokogiri_ruby-1.9.2.320.supp +28 -0
  157. data/suppressions/nokogiri_ruby-1.9.3.327.supp +28 -0
  158. data/tasks/nokogiri.org.rb +24 -0
  159. data/tasks/test.rb +95 -0
  160. data/test/css/test_nthiness.rb +222 -0
  161. data/test/css/test_parser.rb +358 -0
  162. data/test/css/test_tokenizer.rb +198 -0
  163. data/test/css/test_xpath_visitor.rb +96 -0
  164. data/test/decorators/test_slop.rb +16 -0
  165. data/test/files/2ch.html +108 -0
  166. data/test/files/address_book.rlx +12 -0
  167. data/test/files/address_book.xml +10 -0
  168. data/test/files/atom.xml +344 -0
  169. data/test/files/bar/bar.xsd +4 -0
  170. data/test/files/bogus.xml +0 -0
  171. data/test/files/dont_hurt_em_why.xml +422 -0
  172. data/test/files/encoding.html +82 -0
  173. data/test/files/encoding.xhtml +84 -0
  174. data/test/files/exslt.xml +8 -0
  175. data/test/files/exslt.xslt +35 -0
  176. data/test/files/foo/foo.xsd +4 -0
  177. data/test/files/metacharset.html +10 -0
  178. data/test/files/noencoding.html +47 -0
  179. data/test/files/po.xml +32 -0
  180. data/test/files/po.xsd +66 -0
  181. data/test/files/saml/saml20assertion_schema.xsd +283 -0
  182. data/test/files/saml/saml20protocol_schema.xsd +302 -0
  183. data/test/files/saml/xenc_schema.xsd +146 -0
  184. data/test/files/saml/xmldsig_schema.xsd +318 -0
  185. data/test/files/shift_jis.html +10 -0
  186. data/test/files/shift_jis.xml +5 -0
  187. data/test/files/shift_jis_no_charset.html +9 -0
  188. data/test/files/snuggles.xml +3 -0
  189. data/test/files/staff.dtd +10 -0
  190. data/test/files/staff.xml +59 -0
  191. data/test/files/staff.xslt +32 -0
  192. data/test/files/test_document_url/bar.xml +2 -0
  193. data/test/files/test_document_url/document.dtd +4 -0
  194. data/test/files/test_document_url/document.xml +6 -0
  195. data/test/files/tlm.html +850 -0
  196. data/test/files/to_be_xincluded.xml +2 -0
  197. data/test/files/valid_bar.xml +2 -0
  198. data/test/files/xinclude.xml +4 -0
  199. data/test/helper.rb +164 -0
  200. data/test/html/sax/test_parser.rb +141 -0
  201. data/test/html/sax/test_parser_context.rb +46 -0
  202. data/test/html/test_builder.rb +164 -0
  203. data/test/html/test_document.rb +619 -0
  204. data/test/html/test_document_encoding.rb +148 -0
  205. data/test/html/test_document_fragment.rb +261 -0
  206. data/test/html/test_element_description.rb +105 -0
  207. data/test/html/test_named_characters.rb +14 -0
  208. data/test/html/test_node.rb +196 -0
  209. data/test/html/test_node_encoding.rb +27 -0
  210. data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +14 -0
  211. data/test/namespaces/test_namespaces_in_builder_doc.rb +75 -0
  212. data/test/namespaces/test_namespaces_in_cloned_doc.rb +31 -0
  213. data/test/namespaces/test_namespaces_in_created_doc.rb +75 -0
  214. data/test/namespaces/test_namespaces_in_parsed_doc.rb +66 -0
  215. data/test/test_convert_xpath.rb +135 -0
  216. data/test/test_css_cache.rb +45 -0
  217. data/test/test_encoding_handler.rb +46 -0
  218. data/test/test_memory_leak.rb +156 -0
  219. data/test/test_nokogiri.rb +138 -0
  220. data/test/test_reader.rb +558 -0
  221. data/test/test_soap4r_sax.rb +52 -0
  222. data/test/test_xslt_transforms.rb +279 -0
  223. data/test/xml/node/test_save_options.rb +28 -0
  224. data/test/xml/node/test_subclass.rb +44 -0
  225. data/test/xml/sax/test_parser.rb +382 -0
  226. data/test/xml/sax/test_parser_context.rb +115 -0
  227. data/test/xml/sax/test_push_parser.rb +157 -0
  228. data/test/xml/test_attr.rb +64 -0
  229. data/test/xml/test_attribute_decl.rb +86 -0
  230. data/test/xml/test_builder.rb +315 -0
  231. data/test/xml/test_c14n.rb +161 -0
  232. data/test/xml/test_cdata.rb +48 -0
  233. data/test/xml/test_comment.rb +29 -0
  234. data/test/xml/test_document.rb +934 -0
  235. data/test/xml/test_document_encoding.rb +28 -0
  236. data/test/xml/test_document_fragment.rb +228 -0
  237. data/test/xml/test_dtd.rb +187 -0
  238. data/test/xml/test_dtd_encoding.rb +33 -0
  239. data/test/xml/test_element_content.rb +56 -0
  240. data/test/xml/test_element_decl.rb +73 -0
  241. data/test/xml/test_entity_decl.rb +122 -0
  242. data/test/xml/test_entity_reference.rb +245 -0
  243. data/test/xml/test_namespace.rb +95 -0
  244. data/test/xml/test_node.rb +1155 -0
  245. data/test/xml/test_node_attributes.rb +113 -0
  246. data/test/xml/test_node_encoding.rb +107 -0
  247. data/test/xml/test_node_inheritance.rb +32 -0
  248. data/test/xml/test_node_reparenting.rb +374 -0
  249. data/test/xml/test_node_set.rb +755 -0
  250. data/test/xml/test_parse_options.rb +64 -0
  251. data/test/xml/test_processing_instruction.rb +30 -0
  252. data/test/xml/test_reader_encoding.rb +142 -0
  253. data/test/xml/test_relax_ng.rb +60 -0
  254. data/test/xml/test_schema.rb +129 -0
  255. data/test/xml/test_syntax_error.rb +12 -0
  256. data/test/xml/test_text.rb +45 -0
  257. data/test/xml/test_unparented_node.rb +422 -0
  258. data/test/xml/test_xinclude.rb +83 -0
  259. data/test/xml/test_xpath.rb +376 -0
  260. data/test/xslt/test_custom_functions.rb +133 -0
  261. data/test/xslt/test_exception_handling.rb +37 -0
  262. data/test_all +81 -0
  263. metadata +601 -0
@@ -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 if method_defined?(: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 if method_defined?(: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
@@ -0,0 +1,982 @@
1
+ require 'stringio'
2
+ require 'nokogiri/xml/node/save_options'
3
+
4
+ module Nokogiri
5
+ module XML
6
+ ####
7
+ # Nokogiri::XML::Node is your window to the fun filled world of dealing
8
+ # with XML and HTML tags. A Nokogiri::XML::Node may be treated similarly
9
+ # to a hash with regard to attributes. For example (from irb):
10
+ #
11
+ # irb(main):004:0> node
12
+ # => <a href="#foo" id="link">link</a>
13
+ # irb(main):005:0> node['href']
14
+ # => "#foo"
15
+ # irb(main):006:0> node.keys
16
+ # => ["href", "id"]
17
+ # irb(main):007:0> node.values
18
+ # => ["#foo", "link"]
19
+ # irb(main):008:0> node['class'] = 'green'
20
+ # => "green"
21
+ # irb(main):009:0> node
22
+ # => <a href="#foo" id="link" class="green">link</a>
23
+ # irb(main):010:0>
24
+ #
25
+ # See Nokogiri::XML::Node#[] and Nokogiri::XML#[]= for more information.
26
+ #
27
+ # Nokogiri::XML::Node also has methods that let you move around your
28
+ # tree. For navigating your tree, see:
29
+ #
30
+ # * Nokogiri::XML::Node#parent
31
+ # * Nokogiri::XML::Node#children
32
+ # * Nokogiri::XML::Node#next
33
+ # * Nokogiri::XML::Node#previous
34
+ #
35
+ # You may search this node's subtree using Node#xpath and Node#css
36
+ class Node
37
+ include Nokogiri::XML::PP::Node
38
+ include Enumerable
39
+
40
+ # Element node type, see Nokogiri::XML::Node#element?
41
+ ELEMENT_NODE = 1
42
+ # Attribute node type
43
+ ATTRIBUTE_NODE = 2
44
+ # Text node type, see Nokogiri::XML::Node#text?
45
+ TEXT_NODE = 3
46
+ # CDATA node type, see Nokogiri::XML::Node#cdata?
47
+ CDATA_SECTION_NODE = 4
48
+ # Entity reference node type
49
+ ENTITY_REF_NODE = 5
50
+ # Entity node type
51
+ ENTITY_NODE = 6
52
+ # PI node type
53
+ PI_NODE = 7
54
+ # Comment node type, see Nokogiri::XML::Node#comment?
55
+ COMMENT_NODE = 8
56
+ # Document node type, see Nokogiri::XML::Node#xml?
57
+ DOCUMENT_NODE = 9
58
+ # Document type node type
59
+ DOCUMENT_TYPE_NODE = 10
60
+ # Document fragment node type
61
+ DOCUMENT_FRAG_NODE = 11
62
+ # Notation node type
63
+ NOTATION_NODE = 12
64
+ # HTML document node type, see Nokogiri::XML::Node#html?
65
+ HTML_DOCUMENT_NODE = 13
66
+ # DTD node type
67
+ DTD_NODE = 14
68
+ # Element declaration type
69
+ ELEMENT_DECL = 15
70
+ # Attribute declaration type
71
+ ATTRIBUTE_DECL = 16
72
+ # Entity declaration type
73
+ ENTITY_DECL = 17
74
+ # Namespace declaration type
75
+ NAMESPACE_DECL = 18
76
+ # XInclude start type
77
+ XINCLUDE_START = 19
78
+ # XInclude end type
79
+ XINCLUDE_END = 20
80
+ # DOCB document node type
81
+ DOCB_DOCUMENT_NODE = 21
82
+
83
+ def initialize name, document # :nodoc:
84
+ # ... Ya. This is empty on purpose.
85
+ end
86
+
87
+ ###
88
+ # Decorate this node with the decorators set up in this node's Document
89
+ def decorate!
90
+ document.decorate(self)
91
+ end
92
+
93
+ ###
94
+ # Search this node for +paths+. +paths+ can be XPath or CSS, and an
95
+ # optional hash of namespaces may be appended.
96
+ # See Node#xpath and Node#css.
97
+ def search *paths
98
+ # TODO use paths, handler, ns, binds = extract_params(paths)
99
+ ns = paths.last.is_a?(Hash) ? paths.pop :
100
+ (document.root ? document.root.namespaces : {})
101
+
102
+ prefix = "#{implied_xpath_context}/"
103
+
104
+ xpath(*(paths.map { |path|
105
+ path = path.to_s
106
+ path =~ /^(\.\/|\/|\.\.|\.$)/ ? path : CSS.xpath_for(
107
+ path,
108
+ :prefix => prefix,
109
+ :ns => ns
110
+ )
111
+ }.flatten.uniq) + [ns])
112
+ end
113
+ alias :/ :search
114
+
115
+ ###
116
+ # call-seq: xpath *paths, [namespace-bindings, variable-bindings, custom-handler-class]
117
+ #
118
+ # Search this node for XPath +paths+. +paths+ must be one or more XPath
119
+ # queries.
120
+ #
121
+ # node.xpath('.//title')
122
+ #
123
+ # A hash of namespace bindings may be appended. For example:
124
+ #
125
+ # node.xpath('.//foo:name', {'foo' => 'http://example.org/'})
126
+ # node.xpath('.//xmlns:name', node.root.namespaces)
127
+ #
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:
138
+ #
139
+ # node.xpath('.//title[regex(., "\w+")]', Class.new {
140
+ # def regex node_set, regex
141
+ # node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
142
+ # end
143
+ # }.new)
144
+ #
145
+ def xpath *paths
146
+ return NodeSet.new(document) unless document
147
+
148
+ paths, handler, ns, binds = extract_params(paths)
149
+
150
+ sets = paths.map { |path|
151
+ ctx = XPathContext.new(self)
152
+ ctx.register_namespaces(ns)
153
+ path = path.gsub(/xmlns:/, ' :') unless Nokogiri.uses_libxml?
154
+
155
+ binds.each do |key,value|
156
+ ctx.register_variable key.to_s, value
157
+ end if binds
158
+
159
+ ctx.evaluate(path, handler)
160
+ }
161
+ return sets.first if sets.length == 1
162
+
163
+ NodeSet.new(document) do |combined|
164
+ sets.each do |set|
165
+ set.each do |node|
166
+ combined << node
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ ###
173
+ # call-seq: css *rules, [namespace-bindings, custom-pseudo-class]
174
+ #
175
+ # Search this node for CSS +rules+. +rules+ must be one or more CSS
176
+ # selectors. For example:
177
+ #
178
+ # node.css('title')
179
+ # node.css('body h1.bold')
180
+ # node.css('div + p.green', 'div#one')
181
+ #
182
+ # A hash of namespace bindings may be appended. For example:
183
+ #
184
+ # node.css('bike|tire', {'bike' => 'http://schwinn.com/'})
185
+ #
186
+ # Custom CSS pseudo classes may also be defined. To define
187
+ # custom pseudo classes, create a class and implement the custom
188
+ # pseudo class you want defined. The first argument to the
189
+ # method will be the current matching NodeSet. Any other
190
+ # arguments are ones that you pass in. For example:
191
+ #
192
+ # node.css('title:regex("\w+")', Class.new {
193
+ # def regex node_set, regex
194
+ # node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
195
+ # end
196
+ # }.new)
197
+ #
198
+ # Note that the CSS query string is case-sensitive with regards
199
+ # to your document type. That is, if you're looking for "H1" in
200
+ # an HTML document, you'll never find anything, since HTML tags
201
+ # will match only lowercase CSS queries. However, "H1" might be
202
+ # found in an XML document, where tags names are case-sensitive
203
+ # (e.g., "H1" is distinct from "h1").
204
+ #
205
+ def css *rules
206
+ rules, handler, ns, binds = extract_params(rules)
207
+
208
+ prefix = "#{implied_xpath_context}/"
209
+
210
+ rules = rules.map { |rule|
211
+ CSS.xpath_for(rule, :prefix => prefix, :ns => ns)
212
+ }.flatten.uniq + [ns, handler, binds].compact
213
+
214
+ xpath(*rules)
215
+ end
216
+
217
+ ###
218
+ # Search this node's immediate children using CSS selector +selector+
219
+ def > selector
220
+ ns = document.root.namespaces
221
+ xpath CSS.xpath_for(selector, :prefix => "./", :ns => ns).first
222
+ end
223
+
224
+ ###
225
+ # Search for the first occurrence of +path+.
226
+ #
227
+ # Returns nil if nothing is found, otherwise a Node.
228
+ def at path, ns = document.root ? document.root.namespaces : {}
229
+ search(path, ns).first
230
+ end
231
+ alias :% :at
232
+
233
+ ##
234
+ # Search this node for the first occurrence of XPath +paths+.
235
+ # Equivalent to <tt>xpath(paths).first</tt>
236
+ # See Node#xpath for more information.
237
+ #
238
+ def at_xpath *paths
239
+ xpath(*paths).first
240
+ end
241
+
242
+ ##
243
+ # Search this node for the first occurrence of CSS +rules+.
244
+ # Equivalent to <tt>css(rules).first</tt>
245
+ # See Node#css for more information.
246
+ #
247
+ def at_css *rules
248
+ css(*rules).first
249
+ end
250
+
251
+ ###
252
+ # Get the attribute value for the attribute +name+
253
+ def [] name
254
+ get(name.to_s)
255
+ end
256
+
257
+ ###
258
+ # Set the attribute value for the attribute +name+ to +value+
259
+ def []= name, value
260
+ set name.to_s, value.to_s
261
+ end
262
+
263
+ ###
264
+ # Add +node_or_tags+ as a child of this Node.
265
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
266
+ #
267
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
268
+ #
269
+ # Also see related method +<<+.
270
+ def add_child node_or_tags
271
+ node_or_tags = coerce(node_or_tags)
272
+ if node_or_tags.is_a?(XML::NodeSet)
273
+ node_or_tags.each { |n| add_child_node_and_reparent_attrs n }
274
+ else
275
+ add_child_node_and_reparent_attrs node_or_tags
276
+ end
277
+ node_or_tags
278
+ end
279
+
280
+ ###
281
+ # Add +node_or_tags+ as the first child of this Node.
282
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
283
+ #
284
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
285
+ #
286
+ # Also see related method +add_child+.
287
+ def prepend_child node_or_tags
288
+ if first = children.first
289
+ # Mimic the error add_child would raise.
290
+ raise RuntimeError, "Document already has a root node" if is_a?(XML::Document) && !node_or_tags.is_a?(XML::ProcessingInstruction)
291
+ first.__send__(:add_sibling, :previous, node_or_tags)
292
+ else
293
+ add_child(node_or_tags)
294
+ end
295
+ end
296
+
297
+ ###
298
+ # Add +node_or_tags+ as a child of this Node.
299
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
300
+ #
301
+ # Returns self, to support chaining of calls (e.g., root << child1 << child2)
302
+ #
303
+ # Also see related method +add_child+.
304
+ def << node_or_tags
305
+ add_child node_or_tags
306
+ self
307
+ end
308
+ ###
309
+ # Insert +node_or_tags+ before this Node (as a sibling).
310
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
311
+ #
312
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
313
+ #
314
+ # Also see related method +before+.
315
+ def add_previous_sibling node_or_tags
316
+ raise ArgumentError.new("A document may not have multiple root nodes.") if parent.is_a?(XML::Document) && !node_or_tags.is_a?(XML::ProcessingInstruction)
317
+
318
+ add_sibling :previous, node_or_tags
319
+ end
320
+
321
+ ###
322
+ # Insert +node_or_tags+ after this Node (as a sibling).
323
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
324
+ #
325
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
326
+ #
327
+ # Also see related method +after+.
328
+ def add_next_sibling node_or_tags
329
+ raise ArgumentError.new("A document may not have multiple root nodes.") if parent.is_a?(XML::Document)
330
+
331
+ add_sibling :next, node_or_tags
332
+ end
333
+
334
+ ####
335
+ # Insert +node_or_tags+ before this node (as a sibling).
336
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
337
+ #
338
+ # Returns self, to support chaining of calls.
339
+ #
340
+ # Also see related method +add_previous_sibling+.
341
+ def before node_or_tags
342
+ add_previous_sibling node_or_tags
343
+ self
344
+ end
345
+
346
+ ####
347
+ # Insert +node_or_tags+ after this node (as a sibling).
348
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
349
+ #
350
+ # Returns self, to support chaining of calls.
351
+ #
352
+ # Also see related method +add_next_sibling+.
353
+ def after node_or_tags
354
+ add_next_sibling node_or_tags
355
+ self
356
+ end
357
+
358
+ ####
359
+ # Set the inner html for this Node to +node_or_tags+
360
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
361
+ #
362
+ # Returns self.
363
+ #
364
+ # Also see related method +children=+
365
+ def inner_html= node_or_tags
366
+ self.children = node_or_tags
367
+ self
368
+ end
369
+
370
+ ####
371
+ # Set the inner html for this Node +node_or_tags+
372
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
373
+ #
374
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
375
+ #
376
+ # Also see related method +inner_html=+
377
+ def children= node_or_tags
378
+ node_or_tags = coerce(node_or_tags)
379
+ children.unlink
380
+ if node_or_tags.is_a?(XML::NodeSet)
381
+ node_or_tags.each { |n| add_child_node_and_reparent_attrs n }
382
+ else
383
+ add_child_node_and_reparent_attrs node_or_tags
384
+ end
385
+ node_or_tags
386
+ end
387
+
388
+ ####
389
+ # Replace this Node with +node_or_tags+.
390
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
391
+ #
392
+ # Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
393
+ #
394
+ # Also see related method +swap+.
395
+ def replace node_or_tags
396
+ # We cannot replace a text node directly, otherwise libxml will return
397
+ # an internal error at parser.c:13031, I don't know exactly why
398
+ # libxml is trying to find a parent node that is an element or document
399
+ # so I can't tell if this is bug in libxml or not. issue #775.
400
+ if text?
401
+ replacee = Nokogiri::XML::Node.new 'dummy', document
402
+ add_previous_sibling_node replacee
403
+ unlink
404
+ return replacee.replace node_or_tags
405
+ end
406
+
407
+ node_or_tags = coerce(node_or_tags)
408
+
409
+ if node_or_tags.is_a?(XML::NodeSet)
410
+ node_or_tags.each { |n| add_previous_sibling n }
411
+ unlink
412
+ else
413
+ replace_node node_or_tags
414
+ end
415
+ node_or_tags
416
+ end
417
+
418
+ ####
419
+ # Swap this Node for +node_or_tags+
420
+ # +node_or_tags+ can be a Nokogiri::XML::Node, a ::DocumentFragment, a ::NodeSet, or a string containing markup.
421
+ #
422
+ # Returns self, to support chaining of calls.
423
+ #
424
+ # Also see related method +replace+.
425
+ def swap node_or_tags
426
+ replace node_or_tags
427
+ self
428
+ end
429
+
430
+ alias :next :next_sibling
431
+ alias :previous :previous_sibling
432
+
433
+ # :stopdoc:
434
+ # HACK: This is to work around an RDoc bug
435
+ alias :next= :add_next_sibling
436
+ # :startdoc:
437
+
438
+ alias :previous= :add_previous_sibling
439
+ alias :remove :unlink
440
+ alias :get_attribute :[]
441
+ alias :attr :[]
442
+ alias :set_attribute :[]=
443
+ alias :text :content
444
+ alias :inner_text :content
445
+ alias :has_attribute? :key?
446
+ alias :name :node_name
447
+ alias :name= :node_name=
448
+ alias :type :node_type
449
+ alias :to_str :text
450
+ alias :clone :dup
451
+ alias :elements :element_children
452
+
453
+ ####
454
+ # Returns a hash containing the node's attributes. The key is
455
+ # the attribute name without any namespace, the value is a Nokogiri::XML::Attr
456
+ # representing the attribute.
457
+ # If you need to distinguish attributes with the same name, with different namespaces
458
+ # use #attribute_nodes instead.
459
+ def attributes
460
+ Hash[attribute_nodes.map { |node|
461
+ [node.node_name, node]
462
+ }]
463
+ end
464
+
465
+ ###
466
+ # Get the attribute values for this Node.
467
+ def values
468
+ attribute_nodes.map { |node| node.value }
469
+ end
470
+
471
+ ###
472
+ # Get the attribute names for this Node.
473
+ def keys
474
+ attribute_nodes.map { |node| node.node_name }
475
+ end
476
+
477
+ ###
478
+ # Iterate over each attribute name and value pair for this Node.
479
+ def each
480
+ attribute_nodes.each { |node|
481
+ yield [node.node_name, node.value]
482
+ }
483
+ end
484
+
485
+ ###
486
+ # Remove the attribute named +name+
487
+ def remove_attribute name
488
+ attributes[name].remove if key? name
489
+ end
490
+ alias :delete :remove_attribute
491
+
492
+ ###
493
+ # Returns true if this Node matches +selector+
494
+ def matches? selector
495
+ ancestors.last.search(selector).include?(self)
496
+ end
497
+
498
+ ###
499
+ # Create a DocumentFragment containing +tags+ that is relative to _this_
500
+ # context node.
501
+ def fragment tags
502
+ type = document.html? ? Nokogiri::HTML : Nokogiri::XML
503
+ type::DocumentFragment.new(document, tags, self)
504
+ end
505
+
506
+ ###
507
+ # Parse +string_or_io+ as a document fragment within the context of
508
+ # *this* node. Returns a XML::NodeSet containing the nodes parsed from
509
+ # +string_or_io+.
510
+ def parse string_or_io, options = nil
511
+ ##
512
+ # When the current node is unparented and not an element node, use the
513
+ # document as the parsing context instead. Otherwise, the in-context
514
+ # parser cannot find an element or a document node.
515
+ # Document Fragments are also not usable by the in-context parser.
516
+ if !element? && !xml? && (!parent || parent.fragment?)
517
+ return document.parse(string_or_io, options)
518
+ end
519
+
520
+ options ||= (document.html? ? ParseOptions::DEFAULT_HTML : ParseOptions::DEFAULT_XML)
521
+ if Fixnum === options
522
+ options = Nokogiri::XML::ParseOptions.new(options)
523
+ end
524
+ # Give the options to the user
525
+ yield options if block_given?
526
+
527
+ contents = string_or_io.respond_to?(:read) ?
528
+ string_or_io.read :
529
+ string_or_io
530
+
531
+ return Nokogiri::XML::NodeSet.new(document) if contents.empty?
532
+
533
+ ##
534
+ # This is a horrible hack, but I don't care. See #313 for background.
535
+ error_count = document.errors.length
536
+ node_set = in_context(contents, options.to_i)
537
+ if node_set.empty? and document.errors.length > error_count and options.recover?
538
+ fragment = Nokogiri::HTML::DocumentFragment.parse contents
539
+ node_set = fragment.children
540
+ end
541
+ node_set
542
+ end
543
+
544
+ ####
545
+ # Set the Node's content to a Text node containing +string+. The string gets XML escaped, not interpreted as markup.
546
+ def content= string
547
+ self.native_content = encode_special_chars(string.to_s)
548
+ end
549
+
550
+ ###
551
+ # Set the parent Node for this Node
552
+ def parent= parent_node
553
+ parent_node.add_child(self)
554
+ parent_node
555
+ end
556
+
557
+ ###
558
+ # Returns a Hash of {prefix => value} for all namespaces on this
559
+ # node and its ancestors.
560
+ #
561
+ # This method returns the same namespaces as #namespace_scopes.
562
+ #
563
+ # Returns namespaces in scope for self -- those defined on self
564
+ # element directly or any ancestor node -- as a Hash of
565
+ # attribute-name/value pairs. Note that the keys in this hash
566
+ # XML attributes that would be used to define this namespace,
567
+ # such as "xmlns:prefix", not just the prefix. Default namespace
568
+ # set on self will be included with key "xmlns". However,
569
+ # default namespaces set on ancestor will NOT be, even if self
570
+ # has no explicit default namespace.
571
+ def namespaces
572
+ Hash[namespace_scopes.map { |nd|
573
+ key = ['xmlns', nd.prefix].compact.join(':')
574
+ if RUBY_VERSION >= '1.9' && document.encoding
575
+ begin
576
+ key.force_encoding document.encoding
577
+ rescue ArgumentError
578
+ end
579
+ end
580
+ [key, nd.href]
581
+ }]
582
+ end
583
+
584
+ # Returns true if this is a Comment
585
+ def comment?
586
+ type == COMMENT_NODE
587
+ end
588
+
589
+ # Returns true if this is a CDATA
590
+ def cdata?
591
+ type == CDATA_SECTION_NODE
592
+ end
593
+
594
+ # Returns true if this is an XML::Document node
595
+ def xml?
596
+ type == DOCUMENT_NODE
597
+ end
598
+
599
+ # Returns true if this is an HTML::Document node
600
+ def html?
601
+ type == HTML_DOCUMENT_NODE
602
+ end
603
+
604
+ # Returns true if this is a Text node
605
+ def text?
606
+ type == TEXT_NODE
607
+ end
608
+
609
+ # Returns true if this is a DocumentFragment
610
+ def fragment?
611
+ type == DOCUMENT_FRAG_NODE
612
+ end
613
+
614
+ ###
615
+ # Fetch the Nokogiri::HTML::ElementDescription for this node. Returns
616
+ # nil on XML documents and on unknown tags.
617
+ def description
618
+ return nil if document.xml?
619
+ Nokogiri::HTML::ElementDescription[name]
620
+ end
621
+
622
+ ###
623
+ # Is this a read only node?
624
+ def read_only?
625
+ # According to gdome2, these are read-only node types
626
+ [NOTATION_NODE, ENTITY_NODE, ENTITY_DECL].include?(type)
627
+ end
628
+
629
+ # Returns true if this is an Element node
630
+ def element?
631
+ type == ELEMENT_NODE
632
+ end
633
+ alias :elem? :element?
634
+
635
+ ###
636
+ # Turn this node in to a string. If the document is HTML, this method
637
+ # returns html. If the document is XML, this method returns XML.
638
+ def to_s
639
+ document.xml? ? to_xml : to_html
640
+ end
641
+
642
+ # Get the inner_html for this node's Node#children
643
+ def inner_html *args
644
+ children.map { |x| x.to_html(*args) }.join
645
+ end
646
+
647
+ # Get the path to this node as a CSS expression
648
+ def css_path
649
+ path.split(/\//).map { |part|
650
+ part.length == 0 ? nil : part.gsub(/\[(\d+)\]/, ':nth-of-type(\1)')
651
+ }.compact.join(' > ')
652
+ end
653
+
654
+ ###
655
+ # Get a list of ancestor Node for this Node. If +selector+ is given,
656
+ # the ancestors must match +selector+
657
+ def ancestors selector = nil
658
+ return NodeSet.new(document) unless respond_to?(:parent)
659
+ return NodeSet.new(document) unless parent
660
+
661
+ parents = [parent]
662
+
663
+ while parents.last.respond_to?(:parent)
664
+ break unless ctx_parent = parents.last.parent
665
+ parents << ctx_parent
666
+ end
667
+
668
+ return NodeSet.new(document, parents) unless selector
669
+
670
+ root = parents.last
671
+
672
+ NodeSet.new(document, parents.find_all { |parent|
673
+ root.search(selector).include?(parent)
674
+ })
675
+ end
676
+
677
+ ###
678
+ # Adds a default namespace supplied as a string +url+ href, to self.
679
+ # The consequence is as an xmlns attribute with supplied argument were
680
+ # present in parsed XML. A default namespace set with this method will
681
+ # now show up in #attributes, but when this node is serialized to XML an
682
+ # "xmlns" attribute will appear. See also #namespace and #namespace=
683
+ def default_namespace= url
684
+ add_namespace_definition(nil, url)
685
+ end
686
+ alias :add_namespace :add_namespace_definition
687
+
688
+ ###
689
+ # Set the default namespace on this node (as would be defined with an
690
+ # "xmlns=" attribute in XML source), as a Namespace object +ns+. Note that
691
+ # a Namespace added this way will NOT be serialized as an xmlns attribute
692
+ # for this node. You probably want #default_namespace= instead, or perhaps
693
+ # #add_namespace_definition with a nil prefix argument.
694
+ def namespace= ns
695
+ return set_namespace(ns) unless ns
696
+
697
+ unless Nokogiri::XML::Namespace === ns
698
+ raise TypeError, "#{ns.class} can't be coerced into Nokogiri::XML::Namespace"
699
+ end
700
+ if ns.document != document
701
+ raise ArgumentError, 'namespace must be declared on the same document'
702
+ end
703
+
704
+ set_namespace ns
705
+ end
706
+
707
+ ####
708
+ # Yields self and all children to +block+ recursively.
709
+ def traverse &block
710
+ children.each{|j| j.traverse(&block) }
711
+ block.call(self)
712
+ end
713
+
714
+ ###
715
+ # Accept a visitor. This method calls "visit" on +visitor+ with self.
716
+ def accept visitor
717
+ visitor.visit(self)
718
+ end
719
+
720
+ ###
721
+ # Test to see if this Node is equal to +other+
722
+ def == other
723
+ return false unless other
724
+ return false unless other.respond_to?(:pointer_id)
725
+ pointer_id == other.pointer_id
726
+ end
727
+
728
+ ###
729
+ # Serialize Node using +options+. Save options can also be set using a
730
+ # block. See SaveOptions.
731
+ #
732
+ # These two statements are equivalent:
733
+ #
734
+ # node.serialize(:encoding => 'UTF-8', :save_with => FORMAT | AS_XML)
735
+ #
736
+ # or
737
+ #
738
+ # node.serialize(:encoding => 'UTF-8') do |config|
739
+ # config.format.as_xml
740
+ # end
741
+ #
742
+ def serialize *args, &block
743
+ options = args.first.is_a?(Hash) ? args.shift : {
744
+ :encoding => args[0],
745
+ :save_with => args[1]
746
+ }
747
+
748
+ encoding = options[:encoding] || document.encoding
749
+ options[:encoding] = encoding
750
+
751
+ outstring = ""
752
+ if encoding && outstring.respond_to?(:force_encoding)
753
+ outstring.force_encoding(Encoding.find(encoding))
754
+ end
755
+ io = StringIO.new(outstring)
756
+ write_to io, options, &block
757
+ io.string
758
+ end
759
+
760
+ ###
761
+ # Serialize this Node to HTML
762
+ #
763
+ # doc.to_html
764
+ #
765
+ # See Node#write_to for a list of +options+. For formatted output,
766
+ # use Node#to_xhtml instead.
767
+ def to_html options = {}
768
+ to_format SaveOptions::DEFAULT_HTML, options
769
+ end
770
+
771
+ ###
772
+ # Serialize this Node to XML using +options+
773
+ #
774
+ # doc.to_xml(:indent => 5, :encoding => 'UTF-8')
775
+ #
776
+ # See Node#write_to for a list of +options+
777
+ def to_xml options = {}
778
+ options[:save_with] ||= SaveOptions::DEFAULT_XML
779
+ serialize(options)
780
+ end
781
+
782
+ ###
783
+ # Serialize this Node to XHTML using +options+
784
+ #
785
+ # doc.to_xhtml(:indent => 5, :encoding => 'UTF-8')
786
+ #
787
+ # See Node#write_to for a list of +options+
788
+ def to_xhtml options = {}
789
+ to_format SaveOptions::DEFAULT_XHTML, options
790
+ end
791
+
792
+ ###
793
+ # Write Node to +io+ with +options+. +options+ modify the output of
794
+ # this method. Valid options are:
795
+ #
796
+ # * +:encoding+ for changing the encoding
797
+ # * +:indent_text+ the indentation text, defaults to one space
798
+ # * +:indent+ the number of +:indent_text+ to use, defaults to 2
799
+ # * +:save_with+ a combination of SaveOptions constants.
800
+ #
801
+ # To save with UTF-8 indented twice:
802
+ #
803
+ # node.write_to(io, :encoding => 'UTF-8', :indent => 2)
804
+ #
805
+ # To save indented with two dashes:
806
+ #
807
+ # node.write_to(io, :indent_text => '-', :indent => 2
808
+ #
809
+ def write_to io, *options
810
+ options = options.first.is_a?(Hash) ? options.shift : {}
811
+ encoding = options[:encoding] || options[0]
812
+ if Nokogiri.jruby?
813
+ save_options = options[:save_with] || options[1]
814
+ indent_times = options[:indent] || 0
815
+ else
816
+ save_options = options[:save_with] || options[1] || SaveOptions::FORMAT
817
+ indent_times = options[:indent] || 2
818
+ end
819
+ indent_text = options[:indent_text] || ' '
820
+
821
+ config = SaveOptions.new(save_options.to_i)
822
+ yield config if block_given?
823
+
824
+ native_write_to(io, encoding, indent_text * indent_times, config.options)
825
+ end
826
+
827
+ ###
828
+ # Write Node as HTML to +io+ with +options+
829
+ #
830
+ # See Node#write_to for a list of +options+
831
+ def write_html_to io, options = {}
832
+ write_format_to SaveOptions::DEFAULT_HTML, io, options
833
+ end
834
+
835
+ ###
836
+ # Write Node as XHTML to +io+ with +options+
837
+ #
838
+ # See Node#write_to for a list of +options+
839
+ def write_xhtml_to io, options = {}
840
+ write_format_to SaveOptions::DEFAULT_XHTML, io, options
841
+ end
842
+
843
+ ###
844
+ # Write Node as XML to +io+ with +options+
845
+ #
846
+ # doc.write_xml_to io, :encoding => 'UTF-8'
847
+ #
848
+ # See Node#write_to for a list of options
849
+ def write_xml_to io, options = {}
850
+ options[:save_with] ||= SaveOptions::DEFAULT_XML
851
+ write_to io, options
852
+ end
853
+
854
+ ###
855
+ # Compare two Node objects with respect to their Document. Nodes from
856
+ # different documents cannot be compared.
857
+ def <=> other
858
+ return nil unless other.is_a?(Nokogiri::XML::Node)
859
+ return nil unless document == other.document
860
+ compare other
861
+ end
862
+
863
+ ###
864
+ # Do xinclude substitution on the subtree below node. If given a block, a
865
+ # Nokogiri::XML::ParseOptions object initialized from +options+, will be
866
+ # passed to it, allowing more convenient modification of the parser options.
867
+ def do_xinclude options = XML::ParseOptions::DEFAULT_XML, &block
868
+ options = Nokogiri::XML::ParseOptions.new(options) if Fixnum === options
869
+
870
+ # give options to user
871
+ yield options if block_given?
872
+
873
+ # call c extension
874
+ process_xincludes(options.to_i)
875
+ end
876
+
877
+ def canonicalize(mode=XML::XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false)
878
+ c14n_root = self
879
+ document.canonicalize(mode, inclusive_namespaces, with_comments) do |node, parent|
880
+ tn = node.is_a?(XML::Node) ? node : parent
881
+ tn == c14n_root || tn.ancestors.include?(c14n_root)
882
+ end
883
+ end
884
+
885
+ private
886
+
887
+ def add_sibling next_or_previous, node_or_tags
888
+ impl = (next_or_previous == :next) ? :add_next_sibling_node : :add_previous_sibling_node
889
+ iter = (next_or_previous == :next) ? :reverse_each : :each
890
+
891
+ node_or_tags = coerce node_or_tags
892
+ if node_or_tags.is_a?(XML::NodeSet)
893
+ if text?
894
+ pivot = Nokogiri::XML::Node.new 'dummy', document
895
+ send impl, pivot
896
+ else
897
+ pivot = self
898
+ end
899
+ node_or_tags.send(iter) { |n| pivot.send impl, n }
900
+ pivot.unlink if text?
901
+ else
902
+ send impl, node_or_tags
903
+ end
904
+ node_or_tags
905
+ end
906
+
907
+ def to_format save_option, options
908
+ # FIXME: this is a hack around broken libxml versions
909
+ return dump_html if Nokogiri.uses_libxml? && %w[2 6] === LIBXML_VERSION.split('.')[0..1]
910
+
911
+ options[:save_with] = save_option unless options[:save_with]
912
+ serialize(options)
913
+ end
914
+
915
+ def write_format_to save_option, io, options
916
+ # FIXME: this is a hack around broken libxml versions
917
+ return (io << dump_html) if Nokogiri.uses_libxml? && %w[2 6] === LIBXML_VERSION.split('.')[0..1]
918
+
919
+ options[:save_with] ||= save_option
920
+ write_to io, options
921
+ end
922
+
923
+ def extract_params params # :nodoc:
924
+ # Pop off our custom function handler if it exists
925
+ handler = params.find { |param|
926
+ ![Hash, String, Symbol].include?(param.class)
927
+ }
928
+
929
+ params -= [handler] if handler
930
+
931
+ hashes = []
932
+ while Hash === params.last || params.last.nil?
933
+ hashes << params.pop
934
+ break if params.empty?
935
+ end
936
+
937
+ ns, binds = hashes.reverse
938
+
939
+ ns ||= document.root ? document.root.namespaces : {}
940
+
941
+ [params, handler, ns, binds]
942
+ end
943
+
944
+ def coerce data # :nodoc:
945
+ case data
946
+ when XML::NodeSet
947
+ return data
948
+ when XML::DocumentFragment
949
+ return data.children
950
+ when String
951
+ return fragment(data).children
952
+ when Document, XML::Attr
953
+ # unacceptable
954
+ when XML::Node
955
+ return data
956
+ end
957
+
958
+ raise ArgumentError, <<-EOERR
959
+ Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
960
+ (You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
961
+ EOERR
962
+ end
963
+
964
+ def implied_xpath_context
965
+ "./"
966
+ end
967
+
968
+ def inspect_attributes
969
+ [:name, :namespace, :attribute_nodes, :children]
970
+ end
971
+
972
+ def add_child_node_and_reparent_attrs node
973
+ add_child_node node
974
+ node.attribute_nodes.find_all { |a| a.name =~ /:/ }.each do |attr_node|
975
+ attr_node.remove
976
+ node[attr_node.name] = attr_node.value
977
+ end
978
+ end
979
+
980
+ end
981
+ end
982
+ end