nokogiri 1.12.3 → 1.13.1
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.
- checksums.yaml +4 -4
- data/Gemfile +5 -0
- data/README.md +9 -7
- data/bin/nokogiri +63 -50
- data/dependencies.yml +5 -6
- data/ext/nokogiri/extconf.rb +47 -35
- data/ext/nokogiri/xml_document.c +35 -35
- data/ext/nokogiri/xml_document_fragment.c +0 -2
- data/ext/nokogiri/xml_dtd.c +2 -2
- data/ext/nokogiri/xml_encoding_handler.c +25 -11
- data/ext/nokogiri/xml_node.c +645 -333
- data/ext/nokogiri/xml_reader.c +37 -11
- data/ext/nokogiri/xml_xpath_context.c +72 -49
- data/ext/nokogiri/xslt_stylesheet.c +107 -9
- data/gumbo-parser/src/parser.c +0 -11
- data/lib/nokogiri/class_resolver.rb +67 -0
- data/lib/nokogiri/css/node.rb +9 -8
- data/lib/nokogiri/css/parser.rb +360 -341
- data/lib/nokogiri/css/parser.y +249 -244
- data/lib/nokogiri/css/parser_extras.rb +20 -20
- data/lib/nokogiri/css/syntax_error.rb +1 -0
- data/lib/nokogiri/css/tokenizer.rb +4 -3
- data/lib/nokogiri/css/tokenizer.rex +3 -2
- data/lib/nokogiri/css/xpath_visitor.rb +179 -82
- data/lib/nokogiri/css.rb +38 -6
- data/lib/nokogiri/decorators/slop.rb +8 -7
- data/lib/nokogiri/extension.rb +1 -1
- data/lib/nokogiri/gumbo.rb +1 -0
- data/lib/nokogiri/html.rb +16 -10
- data/lib/nokogiri/html4/builder.rb +1 -0
- data/lib/nokogiri/html4/document.rb +84 -75
- data/lib/nokogiri/html4/document_fragment.rb +11 -7
- data/lib/nokogiri/html4/element_description.rb +1 -0
- data/lib/nokogiri/html4/element_description_defaults.rb +426 -520
- data/lib/nokogiri/html4/entity_lookup.rb +2 -1
- data/lib/nokogiri/html4/sax/parser.rb +2 -1
- data/lib/nokogiri/html4/sax/parser_context.rb +1 -0
- data/lib/nokogiri/html4/sax/push_parser.rb +7 -7
- data/lib/nokogiri/html4.rb +11 -5
- data/lib/nokogiri/html5/document.rb +24 -10
- data/lib/nokogiri/html5/document_fragment.rb +5 -2
- data/lib/nokogiri/html5/node.rb +6 -3
- data/lib/nokogiri/html5.rb +68 -64
- data/lib/nokogiri/jruby/dependencies.rb +10 -9
- data/lib/nokogiri/syntax_error.rb +1 -0
- data/lib/nokogiri/version/constant.rb +2 -1
- data/lib/nokogiri/version/info.rb +19 -13
- data/lib/nokogiri/version.rb +1 -0
- data/lib/nokogiri/xml/attr.rb +5 -3
- data/lib/nokogiri/xml/attribute_decl.rb +2 -1
- data/lib/nokogiri/xml/builder.rb +69 -31
- data/lib/nokogiri/xml/cdata.rb +2 -1
- data/lib/nokogiri/xml/character_data.rb +1 -0
- data/lib/nokogiri/xml/document.rb +178 -96
- data/lib/nokogiri/xml/document_fragment.rb +41 -38
- data/lib/nokogiri/xml/dtd.rb +3 -2
- data/lib/nokogiri/xml/element_content.rb +1 -0
- data/lib/nokogiri/xml/element_decl.rb +2 -1
- data/lib/nokogiri/xml/entity_decl.rb +3 -2
- data/lib/nokogiri/xml/entity_reference.rb +1 -0
- data/lib/nokogiri/xml/namespace.rb +2 -0
- data/lib/nokogiri/xml/node/save_options.rb +7 -4
- data/lib/nokogiri/xml/node.rb +512 -348
- data/lib/nokogiri/xml/node_set.rb +46 -54
- data/lib/nokogiri/xml/notation.rb +12 -0
- data/lib/nokogiri/xml/parse_options.rb +11 -7
- data/lib/nokogiri/xml/pp/character_data.rb +8 -6
- data/lib/nokogiri/xml/pp/node.rb +24 -26
- data/lib/nokogiri/xml/pp.rb +1 -0
- data/lib/nokogiri/xml/processing_instruction.rb +2 -1
- data/lib/nokogiri/xml/reader.rb +17 -19
- data/lib/nokogiri/xml/relax_ng.rb +1 -0
- data/lib/nokogiri/xml/sax/document.rb +20 -19
- data/lib/nokogiri/xml/sax/parser.rb +36 -34
- data/lib/nokogiri/xml/sax/parser_context.rb +7 -3
- data/lib/nokogiri/xml/sax/push_parser.rb +5 -5
- data/lib/nokogiri/xml/sax.rb +1 -0
- data/lib/nokogiri/xml/schema.rb +7 -6
- data/lib/nokogiri/xml/searchable.rb +93 -62
- data/lib/nokogiri/xml/syntax_error.rb +4 -4
- data/lib/nokogiri/xml/text.rb +1 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
- data/lib/nokogiri/xml/xpath.rb +12 -0
- data/lib/nokogiri/xml/xpath_context.rb +2 -3
- data/lib/nokogiri/xml.rb +3 -3
- data/lib/nokogiri/xslt/stylesheet.rb +1 -0
- data/lib/nokogiri/xslt.rb +21 -13
- data/lib/nokogiri.rb +19 -16
- data/lib/xsd/xmlparser/nokogiri.rb +25 -24
- data/patches/libxml2/0008-htmlParseComment-handle-abruptly-closed-comments.patch +61 -0
- data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
- metadata +101 -27
@@ -1,18 +1,16 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "pathname"
|
5
5
|
|
6
6
|
module Nokogiri
|
7
7
|
module XML
|
8
|
-
|
9
|
-
# Nokogiri::XML::Document
|
10
|
-
#
|
11
|
-
# See Nokogiri::XML::Document.parse() for more information on parsing.
|
8
|
+
# Nokogiri::XML::Document is the main entry point for dealing with XML documents. The Document
|
9
|
+
# is created by parsing an XML document. See Nokogiri::XML::Document.parse for more information
|
10
|
+
# on parsing.
|
12
11
|
#
|
13
12
|
# For searching a Document, see Nokogiri::XML::Searchable#css and
|
14
13
|
# Nokogiri::XML::Searchable#xpath
|
15
|
-
#
|
16
14
|
class Document < Nokogiri::XML::Node
|
17
15
|
# See http://www.w3.org/TR/REC-xml-names/#ns-decl for more details. Note that we're not
|
18
16
|
# attempting to handle unicode characters partly because libxml2 doesn't handle unicode
|
@@ -47,109 +45,178 @@ module Nokogiri
|
|
47
45
|
#
|
48
46
|
# Nokogiri.XML() is a convenience method which will call this method.
|
49
47
|
#
|
50
|
-
def self.parse
|
48
|
+
def self.parse(string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML)
|
51
49
|
options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
|
52
|
-
|
53
50
|
yield options if block_given?
|
54
51
|
|
55
52
|
url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
|
56
53
|
|
57
54
|
if empty_doc?(string_or_io)
|
58
55
|
if options.strict?
|
59
|
-
raise Nokogiri::XML::SyntaxError
|
56
|
+
raise Nokogiri::XML::SyntaxError, "Empty document"
|
60
57
|
else
|
61
58
|
return encoding ? new.tap { |i| i.encoding = encoding } : new
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
62
|
doc = if string_or_io.respond_to?(:read)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
63
|
+
if string_or_io.is_a?(Pathname)
|
64
|
+
# resolve the Pathname to the file and open it as an IO object, see #2110
|
65
|
+
string_or_io = string_or_io.expand_path.open
|
66
|
+
url ||= string_or_io.path
|
67
|
+
end
|
71
68
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
read_io(string_or_io, url, encoding, options.to_i)
|
70
|
+
else
|
71
|
+
# read_memory pukes on empty docs
|
72
|
+
read_memory(string_or_io, url, encoding, options.to_i)
|
73
|
+
end
|
77
74
|
|
78
75
|
# do xinclude processing
|
79
76
|
doc.do_xinclude(options) if options.xinclude?
|
80
77
|
|
81
|
-
|
78
|
+
doc
|
82
79
|
end
|
83
80
|
|
84
81
|
##
|
85
|
-
#
|
86
|
-
#
|
82
|
+
# :singleton-method: wrap
|
83
|
+
# :call-seq: wrap(java_document) → Nokogiri::XML::Document
|
84
|
+
#
|
85
|
+
# ⚠ This method is only available when running JRuby.
|
87
86
|
#
|
88
|
-
# Create a
|
87
|
+
# Create a Document using an existing Java DOM document object.
|
89
88
|
#
|
90
|
-
# The returned
|
89
|
+
# The returned Document shares the same underlying data structure as the Java object, so
|
91
90
|
# changes in one are reflected in the other.
|
92
91
|
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
92
|
+
# [Parameters]
|
93
|
+
# - `java_document` (Java::OrgW3cDom::Document)
|
94
|
+
# (The class `Java::OrgW3cDom::Document` is also accessible as `org.w3c.dom.Document`.)
|
95
|
+
#
|
96
|
+
# [Returns] Nokogiri::XML::Document
|
97
|
+
#
|
98
|
+
# See also \#to_java
|
98
99
|
|
99
|
-
|
100
|
-
#
|
100
|
+
# :method: to_java
|
101
|
+
# :call-seq: to_java() → Java::OrgW3cDom::Document
|
102
|
+
#
|
103
|
+
# ⚠ This method is only available when running JRuby.
|
101
104
|
#
|
102
|
-
# Returns the underlying Java DOM document object for
|
105
|
+
# Returns the underlying Java DOM document object for this document.
|
103
106
|
#
|
104
|
-
# The returned Java object shares the same underlying data structure as
|
107
|
+
# The returned Java object shares the same underlying data structure as this document, so
|
105
108
|
# changes in one are reflected in the other.
|
106
109
|
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
|
110
|
+
# [Returns]
|
111
|
+
# Java::OrgW3cDom::Document
|
112
|
+
# (The class `Java::OrgW3cDom::Document` is also accessible as `org.w3c.dom.Document`.)
|
113
|
+
#
|
114
|
+
# See also Document.wrap
|
112
115
|
|
113
|
-
#
|
116
|
+
# The errors found while parsing a document.
|
117
|
+
#
|
118
|
+
# [Returns] Array<Nokogiri::XML::SyntaxError>
|
114
119
|
attr_accessor :errors
|
115
120
|
|
116
|
-
|
121
|
+
# When `true`, reparented elements without a namespace will inherit their new parent's
|
122
|
+
# namespace (if one exists). Defaults to `false`.
|
123
|
+
#
|
124
|
+
# [Returns] Boolean
|
125
|
+
#
|
126
|
+
# *Example:* Default behavior of namespace inheritance
|
127
|
+
#
|
128
|
+
# xml = <<~EOF
|
129
|
+
# <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
|
130
|
+
# <foo:parent>
|
131
|
+
# </foo:parent>
|
132
|
+
# </root>
|
133
|
+
# EOF
|
134
|
+
# doc = Nokogiri::XML(xml)
|
135
|
+
# parent = doc.at_xpath("//foo:parent", "foo" => "http://nokogiri.org/default_ns/test/foo")
|
136
|
+
# parent.add_child("<child></child>")
|
137
|
+
# doc.to_xml
|
138
|
+
# # => <?xml version="1.0"?>
|
139
|
+
# # <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
|
140
|
+
# # <foo:parent>
|
141
|
+
# # <child/>
|
142
|
+
# # </foo:parent>
|
143
|
+
# # </root>
|
144
|
+
#
|
145
|
+
# *Example:* Setting namespace inheritance to `true`
|
146
|
+
#
|
147
|
+
# xml = <<~EOF
|
148
|
+
# <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
|
149
|
+
# <foo:parent>
|
150
|
+
# </foo:parent>
|
151
|
+
# </root>
|
152
|
+
# EOF
|
153
|
+
# doc = Nokogiri::XML(xml)
|
154
|
+
# doc.namespace_inheritance = true
|
155
|
+
# parent = doc.at_xpath("//foo:parent", "foo" => "http://nokogiri.org/default_ns/test/foo")
|
156
|
+
# parent.add_child("<child></child>")
|
157
|
+
# doc.to_xml
|
158
|
+
# # => <?xml version="1.0"?>
|
159
|
+
# # <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
|
160
|
+
# # <foo:parent>
|
161
|
+
# # <foo:child/>
|
162
|
+
# # </foo:parent>
|
163
|
+
# # </root>
|
164
|
+
#
|
165
|
+
# Since v1.12.4
|
166
|
+
attr_accessor :namespace_inheritance
|
167
|
+
|
168
|
+
def initialize(*args) # :nodoc:
|
117
169
|
@errors = []
|
118
170
|
@decorators = nil
|
171
|
+
@namespace_inheritance = false
|
119
172
|
end
|
120
173
|
|
121
|
-
|
122
|
-
#
|
123
|
-
#
|
174
|
+
# :call-seq:
|
175
|
+
# create_element(name, *contents_or_attrs, &block) → Nokogiri::XML::Element
|
176
|
+
#
|
177
|
+
# Create a new Element with `name` belonging to this document, optionally setting contents or
|
178
|
+
# attributes.
|
179
|
+
#
|
180
|
+
# This method is _not_ the most user-friendly option if your intention is to add a node to the
|
181
|
+
# document tree. Prefer one of the Nokogiri::XML::Node methods like Node#add_child,
|
182
|
+
# Node#add_next_sibling, Node#replace, etc. which will both create an element (or subtree) and
|
183
|
+
# place it in the document tree.
|
124
184
|
#
|
125
185
|
# Arguments may be passed to initialize the element:
|
126
|
-
#
|
127
|
-
# - a
|
186
|
+
#
|
187
|
+
# - a Hash argument will be used to set attributes
|
188
|
+
# - a non-Hash object that responds to \#to_s will be used to set the new node's contents
|
128
189
|
#
|
129
190
|
# A block may be passed to mutate the node.
|
130
191
|
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
192
|
+
# [Parameters]
|
193
|
+
# - `name` (String)
|
194
|
+
# - `contents_or_attrs` (\#to_s, Hash)
|
195
|
+
# [Yields] `node` (Nokogiri::XML::Element)
|
196
|
+
# [Returns] Nokogiri::XML::Element
|
197
|
+
#
|
198
|
+
# *Example:* An empty element without attributes
|
135
199
|
#
|
136
|
-
# @example An empty element without attributes
|
137
200
|
# doc.create_element("div")
|
138
201
|
# # => <div></div>
|
139
202
|
#
|
140
|
-
#
|
203
|
+
# *Example:* An element with contents
|
204
|
+
#
|
141
205
|
# doc.create_element("div", "contents")
|
142
206
|
# # => <div>contents</div>
|
143
207
|
#
|
144
|
-
#
|
208
|
+
# *Example:* An element with attributes
|
209
|
+
#
|
145
210
|
# doc.create_element("div", {"class" => "container"})
|
146
211
|
# # => <div class='container'></div>
|
147
212
|
#
|
148
|
-
#
|
213
|
+
# *Example:* An element with contents and attributes
|
214
|
+
#
|
149
215
|
# doc.create_element("div", "contents", {"class" => "container"})
|
150
216
|
# # => <div class='container'>contents</div>
|
151
217
|
#
|
152
|
-
#
|
218
|
+
# *Example:* Passing a block to mutate the element
|
219
|
+
#
|
153
220
|
# doc.create_element("div") { |node| node["class"] = "blue" if before_noon? }
|
154
221
|
#
|
155
222
|
def create_element(name, *contents_or_attrs, &block)
|
@@ -170,30 +237,30 @@ module Nokogiri
|
|
170
237
|
elm.content = arg
|
171
238
|
end
|
172
239
|
end
|
173
|
-
if ns = elm.namespace_definitions.find { |n| n.prefix.nil? || (n.prefix ==
|
240
|
+
if (ns = elm.namespace_definitions.find { |n| n.prefix.nil? || (n.prefix == "") })
|
174
241
|
elm.namespace = ns
|
175
242
|
end
|
176
243
|
elm
|
177
244
|
end
|
178
245
|
|
179
246
|
# Create a Text Node with +string+
|
180
|
-
def create_text_node
|
181
|
-
Nokogiri::XML::Text.new
|
247
|
+
def create_text_node(string, &block)
|
248
|
+
Nokogiri::XML::Text.new(string.to_s, self, &block)
|
182
249
|
end
|
183
250
|
|
184
251
|
# Create a CDATA Node containing +string+
|
185
|
-
def create_cdata
|
186
|
-
Nokogiri::XML::CDATA.new
|
252
|
+
def create_cdata(string, &block)
|
253
|
+
Nokogiri::XML::CDATA.new(self, string.to_s, &block)
|
187
254
|
end
|
188
255
|
|
189
256
|
# Create a Comment Node containing +string+
|
190
|
-
def create_comment
|
191
|
-
Nokogiri::XML::Comment.new
|
257
|
+
def create_comment(string, &block)
|
258
|
+
Nokogiri::XML::Comment.new(self, string.to_s, &block)
|
192
259
|
end
|
193
260
|
|
194
261
|
# The name of this document. Always returns "document"
|
195
262
|
def name
|
196
|
-
|
263
|
+
"document"
|
197
264
|
end
|
198
265
|
|
199
266
|
# A reference to +self+
|
@@ -201,46 +268,51 @@ module Nokogiri
|
|
201
268
|
self
|
202
269
|
end
|
203
270
|
|
204
|
-
|
205
|
-
#
|
206
|
-
# return them as a hash.
|
271
|
+
# :call-seq:
|
272
|
+
# collect_namespaces() → Hash<String(Namespace#prefix) ⇒ String(Namespace#href)>
|
207
273
|
#
|
208
|
-
#
|
274
|
+
# Recursively get all namespaces from this node and its subtree and return them as a
|
275
|
+
# hash.
|
209
276
|
#
|
210
|
-
#
|
277
|
+
# ⚠ This method will not handle duplicate namespace prefixes, since the return value is a hash.
|
278
|
+
#
|
279
|
+
# Note that this method does an xpath lookup for nodes with namespaces, and as a result the
|
280
|
+
# order (and which duplicate prefix "wins") may be dependent on the implementation of the
|
281
|
+
# underlying XML library.
|
282
|
+
#
|
283
|
+
# *Example:* Basic usage
|
284
|
+
#
|
285
|
+
# Given this document:
|
286
|
+
#
|
287
|
+
# <root xmlns="default" xmlns:foo="bar">
|
211
288
|
# <bar xmlns:hello="world" />
|
212
289
|
# </root>
|
213
290
|
#
|
214
291
|
# This method will return:
|
215
292
|
#
|
216
|
-
# {
|
293
|
+
# {"xmlns:foo"=>"bar", "xmlns"=>"default", "xmlns:hello"=>"world"}
|
294
|
+
#
|
295
|
+
# *Example:* Duplicate prefixes
|
217
296
|
#
|
218
|
-
#
|
219
|
-
# For example, given this document:
|
297
|
+
# Given this document:
|
220
298
|
#
|
221
299
|
# <root xmlns:foo="bar">
|
222
300
|
# <bar xmlns:foo="baz" />
|
223
301
|
# </root>
|
224
302
|
#
|
225
|
-
# The hash returned will
|
303
|
+
# The hash returned will be something like:
|
226
304
|
#
|
227
|
-
#
|
228
|
-
# in the hash.
|
229
|
-
#
|
230
|
-
# Note that this method does an xpath lookup for nodes with
|
231
|
-
# namespaces, and as a result the order may be dependent on the
|
232
|
-
# implementation of the underlying XML library.
|
305
|
+
# {"xmlns:foo" => "baz"}
|
233
306
|
#
|
234
307
|
def collect_namespaces
|
235
|
-
xpath("//namespace::*").
|
236
|
-
hash[["xmlns",ns.prefix].compact.join(":")] = ns.href if ns.prefix != "xml"
|
237
|
-
hash
|
308
|
+
xpath("//namespace::*").each_with_object({}) do |ns, hash|
|
309
|
+
hash[["xmlns", ns.prefix].compact.join(":")] = ns.href if ns.prefix != "xml"
|
238
310
|
end
|
239
311
|
end
|
240
312
|
|
241
313
|
# Get the list of decorators given +key+
|
242
|
-
def decorators
|
243
|
-
@decorators ||=
|
314
|
+
def decorators(key)
|
315
|
+
@decorators ||= {}
|
244
316
|
@decorators[key] ||= []
|
245
317
|
end
|
246
318
|
|
@@ -249,7 +321,7 @@ module Nokogiri
|
|
249
321
|
# the document or +nil+ when there is no DTD.
|
250
322
|
def validate
|
251
323
|
return nil unless internal_subset
|
252
|
-
internal_subset.validate
|
324
|
+
internal_subset.validate(self)
|
253
325
|
end
|
254
326
|
|
255
327
|
##
|
@@ -269,7 +341,7 @@ module Nokogiri
|
|
269
341
|
# ... which does absolutely nothing.
|
270
342
|
#
|
271
343
|
def slop!
|
272
|
-
unless decorators(XML::Node).include?
|
344
|
+
unless decorators(XML::Node).include?(Nokogiri::Decorators::Slop)
|
273
345
|
decorators(XML::Node) << Nokogiri::Decorators::Slop
|
274
346
|
decorate!
|
275
347
|
end
|
@@ -279,16 +351,16 @@ module Nokogiri
|
|
279
351
|
|
280
352
|
##
|
281
353
|
# Apply any decorators to +node+
|
282
|
-
def decorate
|
354
|
+
def decorate(node)
|
283
355
|
return unless @decorators
|
284
|
-
@decorators.each
|
356
|
+
@decorators.each do |klass, list|
|
285
357
|
next unless node.is_a?(klass)
|
286
358
|
list.each { |moodule| node.extend(moodule) }
|
287
|
-
|
359
|
+
end
|
288
360
|
end
|
289
361
|
|
290
|
-
|
291
|
-
|
362
|
+
alias_method :to_xml, :serialize
|
363
|
+
alias_method :clone, :dup
|
292
364
|
|
293
365
|
# Get the hash of namespaces on the root Nokogiri::XML::Node
|
294
366
|
def namespaces
|
@@ -298,16 +370,16 @@ module Nokogiri
|
|
298
370
|
##
|
299
371
|
# Create a Nokogiri::XML::DocumentFragment from +tags+
|
300
372
|
# Returns an empty fragment if +tags+ is nil.
|
301
|
-
def fragment
|
302
|
-
DocumentFragment.new(self, tags,
|
373
|
+
def fragment(tags = nil)
|
374
|
+
DocumentFragment.new(self, tags, root)
|
303
375
|
end
|
304
376
|
|
305
377
|
undef_method :swap, :parent, :namespace, :default_namespace=
|
306
378
|
undef_method :add_namespace_definition, :attributes
|
307
379
|
undef_method :namespace_definitions, :line, :add_namespace
|
308
380
|
|
309
|
-
def add_child
|
310
|
-
raise "A document may not have multiple root nodes." if (root && root.name !=
|
381
|
+
def add_child(node_or_tags)
|
382
|
+
raise "A document may not have multiple root nodes." if (root && root.name != "nokogiri_text_wrapper") && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
311
383
|
node_or_tags = coerce(node_or_tags)
|
312
384
|
if node_or_tags.is_a?(XML::NodeSet)
|
313
385
|
raise "A document may not have multiple root nodes." if node_or_tags.size > 1
|
@@ -316,17 +388,27 @@ module Nokogiri
|
|
316
388
|
super
|
317
389
|
end
|
318
390
|
end
|
319
|
-
|
391
|
+
alias_method :<<, :add_child
|
392
|
+
|
393
|
+
# :call-seq:
|
394
|
+
# xpath_doctype() → Nokogiri::CSS::XPathVisitor::DoctypeConfig
|
395
|
+
#
|
396
|
+
# [Returns] The document type which determines CSS-to-XPath translation.
|
397
|
+
#
|
398
|
+
# See XPathVisitor for more information.
|
399
|
+
def xpath_doctype
|
400
|
+
Nokogiri::CSS::XPathVisitor::DoctypeConfig::XML
|
401
|
+
end
|
320
402
|
|
321
403
|
private
|
322
404
|
|
323
|
-
def self.empty_doc?
|
405
|
+
def self.empty_doc?(string_or_io)
|
324
406
|
string_or_io.nil? ||
|
325
407
|
(string_or_io.respond_to?(:empty?) && string_or_io.empty?) ||
|
326
408
|
(string_or_io.respond_to?(:eof?) && string_or_io.eof?)
|
327
409
|
end
|
328
410
|
|
329
|
-
IMPLIED_XPATH_CONTEXTS = [
|
411
|
+
IMPLIED_XPATH_CONTEXTS = ["//"].freeze # :nodoc:
|
330
412
|
|
331
413
|
def inspect_attributes
|
332
414
|
[:name, :children]
|
@@ -1,28 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Nokogiri
|
3
4
|
module XML
|
4
5
|
class DocumentFragment < Nokogiri::XML::Node
|
6
|
+
####
|
7
|
+
# Create a Nokogiri::XML::DocumentFragment from +tags+
|
8
|
+
def self.parse(tags, options = ParseOptions::DEFAULT_XML, &block)
|
9
|
+
new(XML::Document.new, tags, nil, options, &block)
|
10
|
+
end
|
11
|
+
|
5
12
|
##
|
6
13
|
# Create a new DocumentFragment from +tags+.
|
7
14
|
#
|
8
15
|
# If +ctx+ is present, it is used as a context node for the
|
9
16
|
# subtree created, e.g., namespaces will be resolved relative
|
10
17
|
# to +ctx+.
|
11
|
-
def initialize
|
18
|
+
def initialize(document, tags = nil, ctx = nil, options = ParseOptions::DEFAULT_XML)
|
12
19
|
return self unless tags
|
13
20
|
|
21
|
+
options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
|
22
|
+
yield options if block_given?
|
23
|
+
|
14
24
|
children = if ctx
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
25
|
+
# Fix for issue#490
|
26
|
+
if Nokogiri.jruby?
|
27
|
+
# fix for issue #770
|
28
|
+
ctx.parse("<root #{namespace_declarations(ctx)}>#{tags}</root>", options).children
|
29
|
+
else
|
30
|
+
ctx.parse(tags, options)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
wrapper_doc = XML::Document.parse("<root>#{tags}</root>", nil, nil, options)
|
34
|
+
self.errors = wrapper_doc.errors
|
35
|
+
wrapper_doc.xpath("/root/node()")
|
36
|
+
end
|
26
37
|
children.each { |child| child.parent = self }
|
27
38
|
end
|
28
39
|
|
@@ -40,7 +51,7 @@ module Nokogiri
|
|
40
51
|
###
|
41
52
|
# return the name for DocumentFragment
|
42
53
|
def name
|
43
|
-
|
54
|
+
"#document-fragment"
|
44
55
|
end
|
45
56
|
|
46
57
|
###
|
@@ -52,10 +63,10 @@ module Nokogiri
|
|
52
63
|
###
|
53
64
|
# Convert this DocumentFragment to html
|
54
65
|
# See Nokogiri::XML::NodeSet#to_html
|
55
|
-
def to_html
|
66
|
+
def to_html(*args)
|
56
67
|
if Nokogiri.jruby?
|
57
68
|
options = args.first.is_a?(Hash) ? args.shift : {}
|
58
|
-
|
69
|
+
unless options[:save_with]
|
59
70
|
options[:save_with] = Node::SaveOptions::NO_DECLARATION | Node::SaveOptions::NO_EMPTY_TAGS | Node::SaveOptions::AS_HTML
|
60
71
|
end
|
61
72
|
args.insert(0, options)
|
@@ -66,10 +77,10 @@ module Nokogiri
|
|
66
77
|
###
|
67
78
|
# Convert this DocumentFragment to xhtml
|
68
79
|
# See Nokogiri::XML::NodeSet#to_xhtml
|
69
|
-
def to_xhtml
|
80
|
+
def to_xhtml(*args)
|
70
81
|
if Nokogiri.jruby?
|
71
82
|
options = args.first.is_a?(Hash) ? args.shift : {}
|
72
|
-
|
83
|
+
unless options[:save_with]
|
73
84
|
options[:save_with] = Node::SaveOptions::NO_DECLARATION | Node::SaveOptions::NO_EMPTY_TAGS | Node::SaveOptions::AS_XHTML
|
74
85
|
end
|
75
86
|
args.insert(0, options)
|
@@ -80,7 +91,7 @@ module Nokogiri
|
|
80
91
|
###
|
81
92
|
# Convert this DocumentFragment to xml
|
82
93
|
# See Nokogiri::XML::NodeSet#to_xml
|
83
|
-
def to_xml
|
94
|
+
def to_xml(*args)
|
84
95
|
children.to_xml(*args)
|
85
96
|
end
|
86
97
|
|
@@ -91,7 +102,7 @@ module Nokogiri
|
|
91
102
|
# selectors. For example:
|
92
103
|
#
|
93
104
|
# For more information see Nokogiri::XML::Searchable#css
|
94
|
-
def css
|
105
|
+
def css(*args)
|
95
106
|
if children.any?
|
96
107
|
children.css(*args) # 'children' is a smell here
|
97
108
|
else
|
@@ -110,34 +121,26 @@ module Nokogiri
|
|
110
121
|
# Search this fragment for +paths+. +paths+ must be one or more XPath or CSS queries.
|
111
122
|
#
|
112
123
|
# For more information see Nokogiri::XML::Searchable#search
|
113
|
-
def search
|
124
|
+
def search(*rules)
|
114
125
|
rules, handler, ns, binds = extract_params(rules)
|
115
126
|
|
116
127
|
rules.inject(NodeSet.new(document)) do |set, rule|
|
117
|
-
set
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
128
|
+
set + if Searchable::LOOKS_LIKE_XPATH.match?(rule)
|
129
|
+
xpath(*[rule, ns, handler, binds].compact)
|
130
|
+
else
|
131
|
+
children.css(*[rule, ns, handler].compact) # 'children' is a smell here
|
132
|
+
end
|
122
133
|
end
|
123
134
|
end
|
124
135
|
|
125
|
-
|
126
|
-
|
127
|
-
class << self
|
128
|
-
####
|
129
|
-
# Create a Nokogiri::XML::DocumentFragment from +tags+
|
130
|
-
def parse tags
|
131
|
-
self.new(XML::Document.new, tags)
|
132
|
-
end
|
133
|
-
end
|
136
|
+
alias_method :serialize, :to_s
|
134
137
|
|
135
138
|
# A list of Nokogiri::XML::SyntaxError found when parsing a document
|
136
139
|
def errors
|
137
140
|
document.errors
|
138
141
|
end
|
139
142
|
|
140
|
-
def errors=
|
143
|
+
def errors=(things) # :nodoc:
|
141
144
|
document.errors = things
|
142
145
|
end
|
143
146
|
|
@@ -148,11 +151,11 @@ module Nokogiri
|
|
148
151
|
private
|
149
152
|
|
150
153
|
# fix for issue 770
|
151
|
-
def namespace_declarations
|
154
|
+
def namespace_declarations(ctx)
|
152
155
|
ctx.namespace_scopes.map do |namespace|
|
153
156
|
prefix = namespace.prefix.nil? ? "" : ":#{namespace.prefix}"
|
154
|
-
%
|
155
|
-
end.join
|
157
|
+
%{xmlns#{prefix}="#{namespace.href}"}
|
158
|
+
end.join(" ")
|
156
159
|
end
|
157
160
|
end
|
158
161
|
end
|
data/lib/nokogiri/xml/dtd.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Nokogiri
|
3
4
|
module XML
|
4
5
|
class DTD < Nokogiri::XML::Node
|
@@ -20,13 +21,13 @@ module Nokogiri
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def html_dtd?
|
23
|
-
name.casecmp(
|
24
|
+
name.casecmp("html").zero?
|
24
25
|
end
|
25
26
|
|
26
27
|
def html5_dtd?
|
27
28
|
html_dtd? &&
|
28
29
|
external_id.nil? &&
|
29
|
-
(system_id.nil? || system_id ==
|
30
|
+
(system_id.nil? || system_id == "about:legacy-compat")
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Nokogiri
|
3
4
|
module XML
|
4
5
|
class ElementDecl < Nokogiri::XML::Node
|
@@ -7,7 +8,7 @@ module Nokogiri
|
|
7
8
|
undef_method :line if method_defined?(:line)
|
8
9
|
|
9
10
|
def inspect
|
10
|
-
"#<#{self.class.name}:#{
|
11
|
+
"#<#{self.class.name}:#{format("0x%x", object_id)} #{to_s.inspect}>"
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|