nokogiri 1.12.5 → 1.13.10
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 +2 -0
- data/README.md +9 -7
- data/bin/nokogiri +63 -50
- data/dependencies.yml +13 -64
- data/ext/nokogiri/extconf.rb +81 -46
- data/ext/nokogiri/gumbo.c +1 -1
- data/ext/nokogiri/html4_sax_parser_context.c +2 -3
- data/ext/nokogiri/nokogiri.h +9 -0
- data/ext/nokogiri/xml_attr.c +2 -2
- data/ext/nokogiri/xml_attribute_decl.c +3 -3
- data/ext/nokogiri/xml_cdata.c +1 -1
- data/ext/nokogiri/xml_document.c +41 -37
- data/ext/nokogiri/xml_document_fragment.c +0 -2
- data/ext/nokogiri/xml_dtd.c +10 -10
- data/ext/nokogiri/xml_element_decl.c +3 -3
- data/ext/nokogiri/xml_encoding_handler.c +25 -11
- data/ext/nokogiri/xml_entity_decl.c +5 -5
- data/ext/nokogiri/xml_namespace.c +41 -5
- data/ext/nokogiri/xml_node.c +708 -382
- data/ext/nokogiri/xml_node_set.c +4 -4
- data/ext/nokogiri/xml_reader.c +92 -11
- data/ext/nokogiri/xml_sax_parser_context.c +10 -3
- data/ext/nokogiri/xml_schema.c +3 -3
- data/ext/nokogiri/xml_text.c +1 -1
- data/ext/nokogiri/xml_xpath_context.c +76 -50
- 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 +22 -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 +88 -77
- 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 +5 -2
- 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 +27 -10
- data/lib/nokogiri/html5/document_fragment.rb +5 -2
- data/lib/nokogiri/html5/node.rb +10 -3
- data/lib/nokogiri/html5.rb +69 -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 +20 -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 +34 -32
- data/lib/nokogiri/xml/cdata.rb +2 -1
- data/lib/nokogiri/xml/character_data.rb +1 -0
- data/lib/nokogiri/xml/document.rb +144 -103
- 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 +8 -4
- data/lib/nokogiri/xml/node.rb +521 -351
- data/lib/nokogiri/xml/node_set.rb +50 -54
- data/lib/nokogiri/xml/notation.rb +12 -0
- data/lib/nokogiri/xml/parse_options.rb +12 -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 +20 -24
- 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 +37 -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 +5 -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 +4 -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/0009-allow-wildcard-namespaces.patch +77 -0
- data/patches/libxslt/0001-update-automake-files-for-arm64.patch +2445 -1919
- data/ports/archives/libxml2-2.10.3.tar.xz +0 -0
- data/ports/archives/libxslt-1.1.37.tar.xz +0 -0
- metadata +117 -34
- data/patches/libxml2/0004-use-glibc-strlen.patch +0 -53
- data/patches/libxml2/0006-update-automake-files-for-arm64.patch +0 -2511
- data/patches/libxml2/0007-Fix-XPath-recursion-limit.patch +0 -31
- data/patches/libxslt/0002-Fix-xml2-config-check-in-configure-script.patch +0 -19
- data/ports/archives/libxml2-2.9.12.tar.gz +0 -0
- data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
data/lib/nokogiri/xml/node.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
-
# encoding:
|
1
|
+
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require "stringio"
|
4
5
|
|
5
6
|
module Nokogiri
|
6
7
|
module XML
|
7
|
-
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# Nokogiri::XML::Node is the primary API you'll use to interact with your Document.
|
9
|
+
#
|
10
|
+
# == Attributes
|
11
|
+
#
|
12
|
+
# A Nokogiri::XML::Node may be treated similarly to a hash with regard to attributes. For
|
10
13
|
# example:
|
11
14
|
#
|
12
15
|
# node = Nokogiri::XML::DocumentFragment.parse("<a href='#foo' id='link'>link</a>").at_css("a")
|
@@ -17,41 +20,52 @@ module Nokogiri
|
|
17
20
|
# node['class'] = 'green' # => "green"
|
18
21
|
# node.to_html # => "<a href=\"#foo\" id=\"link\" class=\"green\">link</a>"
|
19
22
|
#
|
20
|
-
# See the method group entitled
|
23
|
+
# See the method group entitled Node@Working+With+Node+Attributes for the full set of methods.
|
24
|
+
#
|
25
|
+
# == Navigation
|
21
26
|
#
|
22
|
-
#
|
23
|
-
# tree. For navigating your tree, see:
|
27
|
+
# Nokogiri::XML::Node also has methods that let you move around your tree:
|
24
28
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# * {#next}
|
28
|
-
# * {#previous}
|
29
|
+
# [#parent, #children, #next, #previous]
|
30
|
+
# Navigate up, down, or through siblings.
|
29
31
|
#
|
30
|
-
#
|
31
|
-
# its subtree), there are a few methods you might want to use:
|
32
|
+
# See the method group entitled Node@Traversing+Document+Structure for the full set of methods.
|
32
33
|
#
|
33
|
-
#
|
34
|
-
#
|
34
|
+
# == Serialization
|
35
|
+
#
|
36
|
+
# When printing or otherwise emitting a document or a node (and its subtree), there are a few
|
37
|
+
# methods you might want to use:
|
38
|
+
#
|
39
|
+
# [#content, #text, #inner_text, #to_str]
|
40
|
+
# These methods will all **emit plaintext**,
|
41
|
+
# meaning that entities will be replaced (e.g., +<+ will be replaced with +<+), meaning
|
35
42
|
# that any sanitizing will likely be un-done in the output.
|
36
43
|
#
|
37
|
-
#
|
38
|
-
# properly-escaped markup
|
39
|
-
# parsers, etc.
|
44
|
+
# [#to_s, #to_xml, #to_html, #inner_html]
|
45
|
+
# These methods will all **emit properly-escaped markup**, meaning that it's suitable for
|
46
|
+
# consumption by browsers, parsers, etc.
|
47
|
+
#
|
48
|
+
# See the method group entitled Node@Serialization+and+Generating+Output for the full set of methods.
|
49
|
+
#
|
50
|
+
# == Searching
|
40
51
|
#
|
41
|
-
# You may search this node's subtree using
|
52
|
+
# You may search this node's subtree using methods like #xpath and #css.
|
53
|
+
#
|
54
|
+
# See the method group entitled Node@Searching+via+XPath+or+CSS+Queries for the full set of methods.
|
42
55
|
#
|
43
56
|
class Node
|
44
57
|
include Nokogiri::XML::PP::Node
|
45
58
|
include Nokogiri::XML::Searchable
|
59
|
+
include Nokogiri::ClassResolver
|
46
60
|
include Enumerable
|
47
61
|
|
48
|
-
# Element node type, see
|
62
|
+
# Element node type, see Nokogiri::XML::Node#element?
|
49
63
|
ELEMENT_NODE = 1
|
50
64
|
# Attribute node type
|
51
65
|
ATTRIBUTE_NODE = 2
|
52
|
-
# Text node type, see
|
66
|
+
# Text node type, see Nokogiri::XML::Node#text?
|
53
67
|
TEXT_NODE = 3
|
54
|
-
# CDATA node type, see
|
68
|
+
# CDATA node type, see Nokogiri::XML::Node#cdata?
|
55
69
|
CDATA_SECTION_NODE = 4
|
56
70
|
# Entity reference node type
|
57
71
|
ENTITY_REF_NODE = 5
|
@@ -59,9 +73,9 @@ module Nokogiri
|
|
59
73
|
ENTITY_NODE = 6
|
60
74
|
# PI node type
|
61
75
|
PI_NODE = 7
|
62
|
-
# Comment node type, see
|
76
|
+
# Comment node type, see Nokogiri::XML::Node#comment?
|
63
77
|
COMMENT_NODE = 8
|
64
|
-
# Document node type, see
|
78
|
+
# Document node type, see Nokogiri::XML::Node#xml?
|
65
79
|
DOCUMENT_NODE = 9
|
66
80
|
# Document type node type
|
67
81
|
DOCUMENT_TYPE_NODE = 10
|
@@ -69,7 +83,7 @@ module Nokogiri
|
|
69
83
|
DOCUMENT_FRAG_NODE = 11
|
70
84
|
# Notation node type
|
71
85
|
NOTATION_NODE = 12
|
72
|
-
# HTML document node type, see
|
86
|
+
# HTML document node type, see Nokogiri::XML::Node#html?
|
73
87
|
HTML_DOCUMENT_NODE = 13
|
74
88
|
# DTD node type
|
75
89
|
DTD_NODE = 14
|
@@ -88,15 +102,29 @@ module Nokogiri
|
|
88
102
|
# DOCB document node type
|
89
103
|
DOCB_DOCUMENT_NODE = 21
|
90
104
|
|
91
|
-
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
105
|
+
#
|
106
|
+
# :call-seq:
|
107
|
+
# new(name, document) -> Nokogiri::XML::Node
|
108
|
+
# new(name, document) { |node| ... } -> Nokogiri::XML::Node
|
109
|
+
#
|
110
|
+
# Create a new node with +name+ that belongs to +document+.
|
111
|
+
#
|
112
|
+
# If you intend to add a node to a document tree, it's likely that you will prefer one of the
|
113
|
+
# Nokogiri::XML::Node methods like #add_child, #add_next_sibling, #replace, etc. which will
|
114
|
+
# both create an element (or subtree) and place it in the document tree.
|
115
|
+
#
|
116
|
+
# Another alternative, if you are concerned about performance, is
|
117
|
+
# Nokogiri::XML::Document#create_element which accepts additional arguments for contents or
|
118
|
+
# attributes but (like this method) avoids parsing markup.
|
119
|
+
#
|
120
|
+
# [Parameters]
|
121
|
+
# - +name+ (String)
|
122
|
+
# - +document+ (Nokogiri::XML::Document) The document to which the the returned node will belong.
|
123
|
+
# [Yields] Nokogiri::XML::Node
|
124
|
+
# [Returns] Nokogiri::XML::Node
|
125
|
+
#
|
98
126
|
def initialize(name, document)
|
99
|
-
# This is intentionally empty.
|
127
|
+
# This is intentionally empty, and sets the method signature for subclasses.
|
100
128
|
end
|
101
129
|
|
102
130
|
###
|
@@ -105,18 +133,7 @@ module Nokogiri
|
|
105
133
|
document.decorate(self)
|
106
134
|
end
|
107
135
|
|
108
|
-
#
|
109
|
-
|
110
|
-
###
|
111
|
-
# Search this node's immediate children using CSS selector +selector+
|
112
|
-
def >(selector)
|
113
|
-
ns = document.root.namespaces
|
114
|
-
xpath CSS.xpath_for(selector, :prefix => "./", :ns => ns).first
|
115
|
-
end
|
116
|
-
|
117
|
-
# @!endgroup
|
118
|
-
|
119
|
-
# @!group Manipulating Document Structure
|
136
|
+
# :section: Manipulating Document Structure
|
120
137
|
|
121
138
|
###
|
122
139
|
# Add +node_or_tags+ as a child of this Node.
|
@@ -128,9 +145,9 @@ module Nokogiri
|
|
128
145
|
def add_child(node_or_tags)
|
129
146
|
node_or_tags = coerce(node_or_tags)
|
130
147
|
if node_or_tags.is_a?(XML::NodeSet)
|
131
|
-
node_or_tags.each { |n| add_child_node_and_reparent_attrs
|
148
|
+
node_or_tags.each { |n| add_child_node_and_reparent_attrs(n) }
|
132
149
|
else
|
133
|
-
add_child_node_and_reparent_attrs
|
150
|
+
add_child_node_and_reparent_attrs(node_or_tags)
|
134
151
|
end
|
135
152
|
node_or_tags
|
136
153
|
end
|
@@ -143,9 +160,10 @@ module Nokogiri
|
|
143
160
|
#
|
144
161
|
# Also see related method +add_child+.
|
145
162
|
def prepend_child(node_or_tags)
|
146
|
-
if first = children.first
|
163
|
+
if (first = children.first)
|
147
164
|
# Mimic the error add_child would raise.
|
148
|
-
raise
|
165
|
+
raise "Document already has a root node" if document? && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
166
|
+
|
149
167
|
first.__send__(:add_sibling, :previous, node_or_tags)
|
150
168
|
else
|
151
169
|
add_child(node_or_tags)
|
@@ -171,7 +189,7 @@ module Nokogiri
|
|
171
189
|
#
|
172
190
|
# Also see related method +add_child+.
|
173
191
|
def <<(node_or_tags)
|
174
|
-
add_child
|
192
|
+
add_child(node_or_tags)
|
175
193
|
self
|
176
194
|
end
|
177
195
|
|
@@ -183,9 +201,10 @@ module Nokogiri
|
|
183
201
|
#
|
184
202
|
# Also see related method +before+.
|
185
203
|
def add_previous_sibling(node_or_tags)
|
186
|
-
raise ArgumentError
|
204
|
+
raise ArgumentError,
|
205
|
+
"A document may not have multiple root nodes." if parent&.document? && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
187
206
|
|
188
|
-
add_sibling
|
207
|
+
add_sibling(:previous, node_or_tags)
|
189
208
|
end
|
190
209
|
|
191
210
|
###
|
@@ -196,9 +215,10 @@ module Nokogiri
|
|
196
215
|
#
|
197
216
|
# Also see related method +after+.
|
198
217
|
def add_next_sibling(node_or_tags)
|
199
|
-
raise ArgumentError
|
218
|
+
raise ArgumentError,
|
219
|
+
"A document may not have multiple root nodes." if parent&.document? && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
200
220
|
|
201
|
-
add_sibling
|
221
|
+
add_sibling(:next, node_or_tags)
|
202
222
|
end
|
203
223
|
|
204
224
|
####
|
@@ -209,7 +229,7 @@ module Nokogiri
|
|
209
229
|
#
|
210
230
|
# Also see related method +add_previous_sibling+.
|
211
231
|
def before(node_or_tags)
|
212
|
-
add_previous_sibling
|
232
|
+
add_previous_sibling(node_or_tags)
|
213
233
|
self
|
214
234
|
end
|
215
235
|
|
@@ -221,7 +241,7 @@ module Nokogiri
|
|
221
241
|
#
|
222
242
|
# Also see related method +add_next_sibling+.
|
223
243
|
def after(node_or_tags)
|
224
|
-
add_next_sibling
|
244
|
+
add_next_sibling(node_or_tags)
|
225
245
|
self
|
226
246
|
end
|
227
247
|
|
@@ -229,30 +249,24 @@ module Nokogiri
|
|
229
249
|
# Set the inner html for this Node to +node_or_tags+
|
230
250
|
# +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
|
231
251
|
#
|
232
|
-
# Returns self.
|
233
|
-
#
|
234
252
|
# Also see related method +children=+
|
235
253
|
def inner_html=(node_or_tags)
|
236
254
|
self.children = node_or_tags
|
237
|
-
self
|
238
255
|
end
|
239
256
|
|
240
257
|
####
|
241
258
|
# Set the inner html for this Node +node_or_tags+
|
242
259
|
# +node_or_tags+ can be a Nokogiri::XML::Node, a Nokogiri::XML::DocumentFragment, or a string containing markup.
|
243
260
|
#
|
244
|
-
# Returns the reparented node (if +node_or_tags+ is a Node), or NodeSet (if +node_or_tags+ is a DocumentFragment, NodeSet, or string).
|
245
|
-
#
|
246
261
|
# Also see related method +inner_html=+
|
247
262
|
def children=(node_or_tags)
|
248
263
|
node_or_tags = coerce(node_or_tags)
|
249
264
|
children.unlink
|
250
265
|
if node_or_tags.is_a?(XML::NodeSet)
|
251
|
-
node_or_tags.each { |n| add_child_node_and_reparent_attrs
|
266
|
+
node_or_tags.each { |n| add_child_node_and_reparent_attrs(n) }
|
252
267
|
else
|
253
|
-
add_child_node_and_reparent_attrs
|
268
|
+
add_child_node_and_reparent_attrs(node_or_tags)
|
254
269
|
end
|
255
|
-
node_or_tags
|
256
270
|
end
|
257
271
|
|
258
272
|
####
|
@@ -270,19 +284,19 @@ module Nokogiri
|
|
270
284
|
# libxml is trying to find a parent node that is an element or document
|
271
285
|
# so I can't tell if this is bug in libxml or not. issue #775.
|
272
286
|
if text?
|
273
|
-
replacee = Nokogiri::XML::Node.new
|
274
|
-
add_previous_sibling_node
|
287
|
+
replacee = Nokogiri::XML::Node.new("dummy", document)
|
288
|
+
add_previous_sibling_node(replacee)
|
275
289
|
unlink
|
276
|
-
return replacee.replace
|
290
|
+
return replacee.replace(node_or_tags)
|
277
291
|
end
|
278
292
|
|
279
293
|
node_or_tags = parent.coerce(node_or_tags)
|
280
294
|
|
281
295
|
if node_or_tags.is_a?(XML::NodeSet)
|
282
|
-
node_or_tags.each { |n| add_previous_sibling
|
296
|
+
node_or_tags.each { |n| add_previous_sibling(n) }
|
283
297
|
unlink
|
284
298
|
else
|
285
|
-
replace_node
|
299
|
+
replace_node(node_or_tags)
|
286
300
|
end
|
287
301
|
node_or_tags
|
288
302
|
end
|
@@ -295,7 +309,7 @@ module Nokogiri
|
|
295
309
|
#
|
296
310
|
# Also see related method +replace+.
|
297
311
|
def swap(node_or_tags)
|
298
|
-
replace
|
312
|
+
replace(node_or_tags)
|
299
313
|
self
|
300
314
|
end
|
301
315
|
|
@@ -309,7 +323,6 @@ module Nokogiri
|
|
309
323
|
# Set the parent Node for this Node
|
310
324
|
def parent=(parent_node)
|
311
325
|
parent_node.add_child(self)
|
312
|
-
parent_node
|
313
326
|
end
|
314
327
|
|
315
328
|
###
|
@@ -338,7 +351,7 @@ module Nokogiri
|
|
338
351
|
raise ArgumentError, "namespace must be declared on the same document"
|
339
352
|
end
|
340
353
|
|
341
|
-
set_namespace
|
354
|
+
set_namespace(ns)
|
342
355
|
end
|
343
356
|
|
344
357
|
###
|
@@ -347,52 +360,159 @@ module Nokogiri
|
|
347
360
|
# passed to it, allowing more convenient modification of the parser options.
|
348
361
|
def do_xinclude(options = XML::ParseOptions::DEFAULT_XML)
|
349
362
|
options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
|
350
|
-
|
351
|
-
# give options to user
|
352
363
|
yield options if block_given?
|
353
364
|
|
354
365
|
# call c extension
|
355
366
|
process_xincludes(options.to_i)
|
356
367
|
end
|
357
368
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
369
|
+
alias_method :next, :next_sibling
|
370
|
+
alias_method :previous, :previous_sibling
|
371
|
+
alias_method :next=, :add_next_sibling
|
372
|
+
alias_method :previous=, :add_previous_sibling
|
373
|
+
alias_method :remove, :unlink
|
374
|
+
alias_method :name=, :node_name=
|
375
|
+
alias_method :add_namespace, :add_namespace_definition
|
365
376
|
|
366
|
-
#
|
377
|
+
# :section:
|
367
378
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
379
|
+
alias_method :inner_text, :content
|
380
|
+
alias_method :text, :content
|
381
|
+
alias_method :to_str, :content
|
382
|
+
alias_method :name, :node_name
|
383
|
+
alias_method :type, :node_type
|
384
|
+
alias_method :clone, :dup
|
385
|
+
alias_method :elements, :element_children
|
375
386
|
|
376
|
-
#
|
387
|
+
# :section: Working With Node Attributes
|
377
388
|
|
378
|
-
|
379
|
-
#
|
389
|
+
# :call-seq: [](name) → (String, nil)
|
390
|
+
#
|
391
|
+
# Fetch an attribute from this node.
|
392
|
+
#
|
393
|
+
# ⚠ Note that attributes with namespaces cannot be accessed with this method. To access
|
394
|
+
# namespaced attributes, use #attribute_with_ns.
|
395
|
+
#
|
396
|
+
# [Returns] (String, nil) value of the attribute +name+, or +nil+ if no matching attribute exists
|
397
|
+
#
|
398
|
+
# *Example*
|
399
|
+
#
|
400
|
+
# doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
|
401
|
+
# child = doc.at_css("child")
|
402
|
+
# child["size"] # => "large"
|
403
|
+
# child["class"] # => "big wide tall"
|
404
|
+
#
|
405
|
+
# *Example:* Namespaced attributes will not be returned.
|
406
|
+
#
|
407
|
+
# ⚠ Note namespaced attributes may be accessed with #attribute or #attribute_with_ns
|
408
|
+
#
|
409
|
+
# doc = Nokogiri::XML(<<~EOF)
|
410
|
+
# <root xmlns:width='http://example.com/widths'>
|
411
|
+
# <child width:size='broad'/>
|
412
|
+
# </root>
|
413
|
+
# EOF
|
414
|
+
# doc.at_css("child")["size"] # => nil
|
415
|
+
# doc.at_css("child").attribute("size").value # => "broad"
|
416
|
+
# doc.at_css("child").attribute_with_ns("size", "http://example.com/widths").value
|
417
|
+
# # => "broad"
|
418
|
+
#
|
380
419
|
def [](name)
|
381
420
|
get(name.to_s)
|
382
421
|
end
|
383
422
|
|
384
|
-
|
385
|
-
#
|
423
|
+
# :call-seq: []=(name, value) → value
|
424
|
+
#
|
425
|
+
# Update the attribute +name+ to +value+, or create the attribute if it does not exist.
|
426
|
+
#
|
427
|
+
# ⚠ Note that attributes with namespaces cannot be accessed with this method. To access
|
428
|
+
# namespaced attributes for update, use #attribute_with_ns. To add a namespaced attribute,
|
429
|
+
# see the example below.
|
430
|
+
#
|
431
|
+
# [Returns] +value+
|
432
|
+
#
|
433
|
+
# *Example*
|
434
|
+
#
|
435
|
+
# doc = Nokogiri::XML("<root><child/></root>")
|
436
|
+
# child = doc.at_css("child")
|
437
|
+
# child["size"] = "broad"
|
438
|
+
# child.to_html
|
439
|
+
# # => "<child size=\"broad\"></child>"
|
440
|
+
#
|
441
|
+
# *Example:* Add a namespaced attribute.
|
442
|
+
#
|
443
|
+
# doc = Nokogiri::XML(<<~EOF)
|
444
|
+
# <root xmlns:width='http://example.com/widths'>
|
445
|
+
# <child/>
|
446
|
+
# </root>
|
447
|
+
# EOF
|
448
|
+
# child = doc.at_css("child")
|
449
|
+
# child["size"] = "broad"
|
450
|
+
# ns = doc.root.namespace_definitions.find { |ns| ns.prefix == "width" }
|
451
|
+
# child.attribute("size").namespace = ns
|
452
|
+
# doc.to_html
|
453
|
+
# # => "<root xmlns:width=\"http://example.com/widths\">\n" +
|
454
|
+
# # " <child width:size=\"broad\"></child>\n" +
|
455
|
+
# # "</root>\n"
|
456
|
+
#
|
386
457
|
def []=(name, value)
|
387
|
-
set
|
458
|
+
set(name.to_s, value.to_s)
|
388
459
|
end
|
389
460
|
|
390
|
-
|
391
|
-
#
|
392
|
-
#
|
393
|
-
#
|
394
|
-
#
|
395
|
-
#
|
461
|
+
#
|
462
|
+
# :call-seq: attributes() → Hash<String ⇒ Nokogiri::XML::Attr>
|
463
|
+
#
|
464
|
+
# Fetch this node's attributes.
|
465
|
+
#
|
466
|
+
# ⚠ Because the keys do not include any namespace information for the attribute, in case of a
|
467
|
+
# simple name collision, not all attributes will be returned. In this case, you will need to
|
468
|
+
# use #attribute_nodes.
|
469
|
+
#
|
470
|
+
# [Returns]
|
471
|
+
# Hash containing attributes belonging to +self+. The hash keys are String attribute
|
472
|
+
# names (without the namespace), and the hash values are Nokogiri::XML::Attr.
|
473
|
+
#
|
474
|
+
# *Example* with no namespaces:
|
475
|
+
#
|
476
|
+
# doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
|
477
|
+
# doc.at_css("child").attributes
|
478
|
+
# # => {"size"=>#(Attr:0x550 { name = "size", value = "large" }),
|
479
|
+
# # "class"=>#(Attr:0x564 { name = "class", value = "big wide tall" })}
|
480
|
+
#
|
481
|
+
# *Example* with a namespace:
|
482
|
+
#
|
483
|
+
# doc = Nokogiri::XML("<root xmlns:desc='http://example.com/sizes'><child desc:size='large'/></root>")
|
484
|
+
# doc.at_css("child").attributes
|
485
|
+
# # => {"size"=>
|
486
|
+
# # #(Attr:0x550 {
|
487
|
+
# # name = "size",
|
488
|
+
# # namespace = #(Namespace:0x564 {
|
489
|
+
# # prefix = "desc",
|
490
|
+
# # href = "http://example.com/sizes"
|
491
|
+
# # }),
|
492
|
+
# # value = "large"
|
493
|
+
# # })}
|
494
|
+
#
|
495
|
+
# *Example* with an attribute name collision:
|
496
|
+
#
|
497
|
+
# ⚠ Note that only one of the attributes is returned in the Hash.
|
498
|
+
#
|
499
|
+
# doc = Nokogiri::XML(<<~EOF)
|
500
|
+
# <root xmlns:width='http://example.com/widths'
|
501
|
+
# xmlns:height='http://example.com/heights'>
|
502
|
+
# <child width:size='broad' height:size='tall'/>
|
503
|
+
# </root>
|
504
|
+
# EOF
|
505
|
+
# doc.at_css("child").attributes
|
506
|
+
# # => {"size"=>
|
507
|
+
# # #(Attr:0x550 {
|
508
|
+
# # name = "size",
|
509
|
+
# # namespace = #(Namespace:0x564 {
|
510
|
+
# # prefix = "height",
|
511
|
+
# # href = "http://example.com/heights"
|
512
|
+
# # }),
|
513
|
+
# # value = "tall"
|
514
|
+
# # })}
|
515
|
+
#
|
396
516
|
def attributes
|
397
517
|
attribute_nodes.each_with_object({}) do |node, hash|
|
398
518
|
hash[node.node_name] = node
|
@@ -408,7 +528,7 @@ module Nokogiri
|
|
408
528
|
###
|
409
529
|
# Does this Node's attributes include <value>
|
410
530
|
def value?(value)
|
411
|
-
values.include?
|
531
|
+
values.include?(value)
|
412
532
|
end
|
413
533
|
|
414
534
|
###
|
@@ -420,36 +540,36 @@ module Nokogiri
|
|
420
540
|
###
|
421
541
|
# Iterate over each attribute name and value pair for this Node.
|
422
542
|
def each
|
423
|
-
attribute_nodes.each
|
543
|
+
attribute_nodes.each do |node|
|
424
544
|
yield [node.node_name, node.value]
|
425
|
-
|
545
|
+
end
|
426
546
|
end
|
427
547
|
|
428
548
|
###
|
429
549
|
# Remove the attribute named +name+
|
430
550
|
def remove_attribute(name)
|
431
|
-
attr = attributes[name].remove if key?
|
551
|
+
attr = attributes[name].remove if key?(name)
|
432
552
|
clear_xpath_context if Nokogiri.jruby?
|
433
553
|
attr
|
434
554
|
end
|
435
555
|
|
436
|
-
#
|
556
|
+
#
|
557
|
+
# :call-seq: classes() → Array<String>
|
558
|
+
#
|
559
|
+
# Fetch CSS class names of a Node.
|
437
560
|
#
|
438
561
|
# This is a convenience function and is equivalent to:
|
562
|
+
#
|
439
563
|
# node.kwattr_values("class")
|
440
564
|
#
|
441
|
-
#
|
442
|
-
# @see #add_class
|
443
|
-
# @see #append_class
|
444
|
-
# @see #remove_class
|
565
|
+
# See related: #kwattr_values, #add_class, #append_class, #remove_class
|
445
566
|
#
|
446
|
-
#
|
567
|
+
# [Returns]
|
568
|
+
# The CSS classes (Array of String) present in the Node's "class" attribute. If the
|
569
|
+
# attribute is empty or non-existent, the return value is an empty array.
|
447
570
|
#
|
448
|
-
#
|
449
|
-
# the attribute is empty or non-existent, the return value is
|
450
|
-
# an empty array.
|
571
|
+
# *Example*
|
451
572
|
#
|
452
|
-
# @example
|
453
573
|
# node # => <div class="section title header"></div>
|
454
574
|
# node.classes # => ["section", "title", "header"]
|
455
575
|
#
|
@@ -457,42 +577,45 @@ module Nokogiri
|
|
457
577
|
kwattr_values("class")
|
458
578
|
end
|
459
579
|
|
460
|
-
#
|
461
|
-
#
|
462
|
-
#
|
463
|
-
#
|
464
|
-
#
|
580
|
+
#
|
581
|
+
# :call-seq: add_class(names) → self
|
582
|
+
#
|
583
|
+
# Ensure HTML CSS classes are present on +self+. Any CSS classes in +names+ that already exist
|
584
|
+
# in the "class" attribute are _not_ added. Note that any existing duplicates in the
|
585
|
+
# "class" attribute are not removed. Compare with #append_class.
|
465
586
|
#
|
466
587
|
# This is a convenience function and is equivalent to:
|
588
|
+
#
|
467
589
|
# node.kwattr_add("class", names)
|
468
590
|
#
|
469
|
-
#
|
470
|
-
#
|
471
|
-
#
|
472
|
-
#
|
591
|
+
# See related: #kwattr_add, #classes, #append_class, #remove_class
|
592
|
+
#
|
593
|
+
# [Parameters]
|
594
|
+
# - +names+ (String, Array<String>)
|
473
595
|
#
|
474
|
-
#
|
596
|
+
# CSS class names to be added to the Node's "class" attribute. May be a string containing
|
597
|
+
# whitespace-delimited names, or an Array of String names. Any class names already present
|
598
|
+
# will not be added. Any class names not present will be added. If no "class" attribute
|
599
|
+
# exists, one is created.
|
475
600
|
#
|
476
|
-
#
|
477
|
-
# attribute. May be a string containing whitespace-delimited
|
478
|
-
# names, or an Array of String names. Any class names already
|
479
|
-
# present will not be added. Any class names not present will
|
480
|
-
# be added. If no +class+ attribute exists, one is created.
|
601
|
+
# [Returns] +self+ (Node) for ease of chaining method calls.
|
481
602
|
#
|
482
|
-
#
|
603
|
+
# *Example:* Ensure that the node has CSS class "section"
|
483
604
|
#
|
484
|
-
# @example Ensure that a +Node+ has CSS class "section"
|
485
605
|
# node # => <div></div>
|
486
606
|
# node.add_class("section") # => <div class="section"></div>
|
487
607
|
# node.add_class("section") # => <div class="section"></div> # duplicate not added
|
488
608
|
#
|
489
|
-
#
|
609
|
+
# *Example:* Ensure that the node has CSS classes "section" and "header", via a String argument
|
610
|
+
#
|
611
|
+
# Note that the CSS class "section" is not added because it is already present.
|
612
|
+
# Note also that the pre-existing duplicate CSS class "section" is not removed.
|
613
|
+
#
|
490
614
|
# node # => <div class="section section"></div>
|
491
615
|
# node.add_class("section header") # => <div class="section section header"></div>
|
492
|
-
# # Note that the CSS class "section" is not added because it is already present.
|
493
|
-
# # Note also that the pre-existing duplicate CSS class "section" is not removed.
|
494
616
|
#
|
495
|
-
#
|
617
|
+
# *Example:* Ensure that the node has CSS classes "section" and "header", via an Array argument
|
618
|
+
#
|
496
619
|
# node # => <div></div>
|
497
620
|
# node.add_class(["section", "header"]) # => <div class="section header"></div>
|
498
621
|
#
|
@@ -500,39 +623,42 @@ module Nokogiri
|
|
500
623
|
kwattr_add("class", names)
|
501
624
|
end
|
502
625
|
|
503
|
-
#
|
504
|
-
#
|
626
|
+
#
|
627
|
+
# :call-seq: append_class(names) → self
|
628
|
+
#
|
629
|
+
# Add HTML CSS classes to +self+, regardless of duplication. Compare with #add_class.
|
505
630
|
#
|
506
631
|
# This is a convenience function and is equivalent to:
|
632
|
+
#
|
507
633
|
# node.kwattr_append("class", names)
|
508
634
|
#
|
509
|
-
#
|
510
|
-
# @see #classes
|
511
|
-
# @see #add_class
|
512
|
-
# @see #remove_class
|
635
|
+
# See related: #kwattr_append, #classes, #add_class, #remove_class
|
513
636
|
#
|
514
|
-
#
|
637
|
+
# [Parameters]
|
638
|
+
# - +names+ (String, Array<String>)
|
515
639
|
#
|
516
|
-
# CSS class names to be appended to the Node's
|
517
|
-
#
|
518
|
-
#
|
519
|
-
#
|
520
|
-
# are already present in the attribute value. If no +class+
|
521
|
-
# attribute exists, one is created.
|
640
|
+
# CSS class names to be appended to the Node's "class" attribute. May be a string containing
|
641
|
+
# whitespace-delimited names, or an Array of String names. All class names passed in will be
|
642
|
+
# appended to the "class" attribute even if they are already present in the attribute
|
643
|
+
# value. If no "class" attribute exists, one is created.
|
522
644
|
#
|
523
|
-
#
|
645
|
+
# [Returns] +self+ (Node) for ease of chaining method calls.
|
646
|
+
#
|
647
|
+
# *Example:* Append "section" to the node's CSS "class" attribute
|
524
648
|
#
|
525
|
-
# @example Append "section" to a +Node+'s CSS +class+ attriubute
|
526
649
|
# node # => <div></div>
|
527
650
|
# node.append_class("section") # => <div class="section"></div>
|
528
651
|
# node.append_class("section") # => <div class="section section"></div> # duplicate added!
|
529
652
|
#
|
530
|
-
#
|
653
|
+
# *Example:* Append "section" and "header" to the noded's CSS "class" attribute, via a String argument
|
654
|
+
#
|
655
|
+
# Note that the CSS class "section" is appended even though it is already present
|
656
|
+
#
|
531
657
|
# node # => <div class="section section"></div>
|
532
658
|
# node.append_class("section header") # => <div class="section section section header"></div>
|
533
|
-
# # Note that the CSS class "section" is appended even though it is already present.
|
534
659
|
#
|
535
|
-
#
|
660
|
+
# *Example:* Append "section" and "header" to the node's CSS "class" attribute, via an Array argument
|
661
|
+
#
|
536
662
|
# node # => <div></div>
|
537
663
|
# node.append_class(["section", "header"]) # => <div class="section header"></div>
|
538
664
|
# node.append_class(["section", "header"]) # => <div class="section header section header"></div>
|
@@ -541,118 +667,135 @@ module Nokogiri
|
|
541
667
|
kwattr_append("class", names)
|
542
668
|
end
|
543
669
|
|
544
|
-
#
|
545
|
-
#
|
546
|
-
# multiple entries.
|
670
|
+
# :call-seq:
|
671
|
+
# remove_class(css_classes) → self
|
547
672
|
#
|
548
|
-
#
|
549
|
-
#
|
673
|
+
# Remove HTML CSS classes from this node. Any CSS class names in +css_classes+ that exist in
|
674
|
+
# this node's "class" attribute are removed, including any multiple entries.
|
675
|
+
#
|
676
|
+
# If no CSS classes remain after this operation, or if +css_classes+ is +nil+, the "class"
|
677
|
+
# attribute is deleted from the node.
|
550
678
|
#
|
551
679
|
# This is a convenience function and is equivalent to:
|
552
|
-
# node.kwattr_remove("class", names)
|
553
680
|
#
|
554
|
-
#
|
555
|
-
#
|
556
|
-
#
|
557
|
-
#
|
681
|
+
# node.kwattr_remove("class", css_classes)
|
682
|
+
#
|
683
|
+
# Also see #kwattr_remove, #classes, #add_class, #append_class
|
684
|
+
#
|
685
|
+
# [Parameters]
|
686
|
+
# - +css_classes+ (String, Array<String>)
|
687
|
+
#
|
688
|
+
# CSS class names to be removed from the Node's
|
689
|
+
# "class" attribute. May be a string containing whitespace-delimited names, or an Array of
|
690
|
+
# String names. Any class names already present will be removed. If no CSS classes remain,
|
691
|
+
# the "class" attribute is deleted.
|
558
692
|
#
|
559
|
-
#
|
693
|
+
# [Returns] +self+ (Nokogiri::XML::Node) for ease of chaining method calls.
|
560
694
|
#
|
561
|
-
#
|
562
|
-
# be a string containing whitespace-delimited names, or an Array of
|
563
|
-
# String names. Any class names already present will be removed. If no
|
564
|
-
# CSS classes remain, the +class+ attribute is deleted.
|
695
|
+
# *Example*: Deleting a CSS class
|
565
696
|
#
|
566
|
-
#
|
697
|
+
# Note that all instances of the class "section" are removed from the "class" attribute.
|
567
698
|
#
|
568
|
-
#
|
569
|
-
# node # => <div class="section header"></div>
|
699
|
+
# node # => <div class="section header section"></div>
|
570
700
|
# node.remove_class("section") # => <div class="header"></div>
|
571
|
-
#
|
701
|
+
#
|
702
|
+
# *Example*: Deleting the only remaining CSS class
|
703
|
+
#
|
704
|
+
# Note that the attribute is removed once there are no remaining classes.
|
705
|
+
#
|
706
|
+
# node # => <div class="section"></div>
|
707
|
+
# node.remove_class("section") # => <div></div>
|
708
|
+
#
|
709
|
+
# *Example*: Deleting multiple CSS classes
|
710
|
+
#
|
711
|
+
# Note that the "class" attribute is deleted once it's empty.
|
712
|
+
#
|
713
|
+
# node # => <div class="section header float"></div>
|
714
|
+
# node.remove_class(["section", "float"]) # => <div class="header"></div>
|
572
715
|
#
|
573
716
|
def remove_class(names = nil)
|
574
717
|
kwattr_remove("class", names)
|
575
718
|
end
|
576
719
|
|
577
|
-
#
|
720
|
+
# :call-seq:
|
721
|
+
# kwattr_values(attribute_name) → Array<String>
|
578
722
|
#
|
579
|
-
#
|
580
|
-
# of space-delimited values. Perhaps the most familiar example
|
581
|
-
# of this is the HTML +class+ attribute used to contain CSS
|
582
|
-
# classes. But other keyword attributes exist, for instance
|
583
|
-
# [`rel`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
|
723
|
+
# Fetch values from a keyword attribute of a Node.
|
584
724
|
#
|
585
|
-
#
|
586
|
-
#
|
587
|
-
#
|
588
|
-
#
|
725
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
726
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
727
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
728
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
589
729
|
#
|
590
|
-
#
|
730
|
+
# See also #classes, #kwattr_add, #kwattr_append, #kwattr_remove
|
591
731
|
#
|
592
|
-
#
|
732
|
+
# [Parameters]
|
733
|
+
# - +attribute_name+ (String) The name of the keyword attribute to be inspected.
|
593
734
|
#
|
594
|
-
#
|
595
|
-
#
|
596
|
-
# return value is an empty array.
|
735
|
+
# [Returns]
|
736
|
+
# (Array<String>) The values present in the Node's +attribute_name+ attribute. If the
|
737
|
+
# attribute is empty or non-existent, the return value is an empty array.
|
738
|
+
#
|
739
|
+
# *Example:*
|
597
740
|
#
|
598
|
-
# @example
|
599
741
|
# node # => <a rel="nofollow noopener external">link</a>
|
600
742
|
# node.kwattr_values("rel") # => ["nofollow", "noopener", "external"]
|
601
743
|
#
|
602
|
-
#
|
603
|
-
#
|
744
|
+
# Since v1.11.0
|
604
745
|
def kwattr_values(attribute_name)
|
605
746
|
keywordify(get_attribute(attribute_name) || [])
|
606
747
|
end
|
607
748
|
|
749
|
+
# :call-seq:
|
750
|
+
# kwattr_add(attribute_name, keywords) → self
|
751
|
+
#
|
608
752
|
# Ensure that values are present in a keyword attribute.
|
609
753
|
#
|
610
|
-
# Any values in +keywords+ that already exist in the
|
611
|
-
#
|
612
|
-
#
|
613
|
-
# with {#kwattr_append}.
|
754
|
+
# Any values in +keywords+ that already exist in the Node's attribute values are _not_
|
755
|
+
# added. Note that any existing duplicates in the attribute values are not removed. Compare
|
756
|
+
# with #kwattr_append.
|
614
757
|
#
|
615
|
-
# A "keyword attribute" is a node attribute that contains a set
|
616
|
-
#
|
617
|
-
#
|
618
|
-
#
|
619
|
-
# [`rel`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
|
758
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
759
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
760
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
761
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
620
762
|
#
|
621
|
-
#
|
622
|
-
# @see #kwattr_values
|
623
|
-
# @see #kwattr_append
|
624
|
-
# @see #kwattr_remove
|
763
|
+
# See also #add_class, #kwattr_values, #kwattr_append, #kwattr_remove
|
625
764
|
#
|
626
|
-
#
|
765
|
+
# [Parameters]
|
766
|
+
# - +attribute_name+ (String) The name of the keyword attribute to be modified.
|
767
|
+
# - +keywords+ (String, Array<String>)
|
768
|
+
# Keywords to be added to the attribute named +attribute_name+. May be a string containing
|
769
|
+
# whitespace-delimited values, or an Array of String values. Any values already present will
|
770
|
+
# not be added. Any values not present will be added. If the named attribute does not exist,
|
771
|
+
# it is created.
|
627
772
|
#
|
628
|
-
#
|
773
|
+
# [Returns] +self+ (Nokogiri::XML::Node) for ease of chaining method calls.
|
629
774
|
#
|
630
|
-
#
|
631
|
-
# +attribute_name+. May be a string containing
|
632
|
-
# whitespace-delimited values, or an Array of String
|
633
|
-
# values. Any values already present will not be added. Any
|
634
|
-
# values not present will be added. If the named attribute
|
635
|
-
# does not exist, it is created.
|
775
|
+
# *Example:* Ensure that a +Node+ has "nofollow" in its +rel+ attribute.
|
636
776
|
#
|
637
|
-
#
|
777
|
+
# Note that duplicates are not added.
|
638
778
|
#
|
639
|
-
# @example Ensure that a +Node+ has "nofollow" in its +rel+ attribute.
|
640
779
|
# node # => <a></a>
|
641
780
|
# node.kwattr_add("rel", "nofollow") # => <a rel="nofollow"></a>
|
642
|
-
# node.kwattr_add("rel", "nofollow") # => <a rel="nofollow"></a>
|
781
|
+
# node.kwattr_add("rel", "nofollow") # => <a rel="nofollow"></a>
|
782
|
+
#
|
783
|
+
# *Example:* Ensure that a +Node+ has "nofollow" and "noreferrer" in its +rel+ attribute, via a
|
784
|
+
# String argument.
|
785
|
+
#
|
786
|
+
# Note that "nofollow" is not added because it is already present. Note also that the
|
787
|
+
# pre-existing duplicate "nofollow" is not removed.
|
643
788
|
#
|
644
|
-
# @example Ensure that a +Node+ has "nofollow" and "noreferrer" in its +rel+ attribute, via a String argument.
|
645
789
|
# node # => <a rel="nofollow nofollow"></a>
|
646
790
|
# node.kwattr_add("rel", "nofollow noreferrer") # => <a rel="nofollow nofollow noreferrer"></a>
|
647
|
-
# # Note that "nofollow" is not added because it is already present.
|
648
|
-
# # Note also that the pre-existing duplicate "nofollow" is not removed.
|
649
791
|
#
|
650
|
-
#
|
792
|
+
# *Example:* Ensure that a +Node+ has "nofollow" and "noreferrer" in its +rel+ attribute, via
|
793
|
+
# an Array argument.
|
794
|
+
#
|
651
795
|
# node # => <a></a>
|
652
796
|
# node.kwattr_add("rel", ["nofollow", "noreferrer"]) # => <a rel="nofollow noreferrer"></a>
|
653
797
|
#
|
654
|
-
#
|
655
|
-
#
|
798
|
+
# Since v1.11.0
|
656
799
|
def kwattr_add(attribute_name, keywords)
|
657
800
|
keywords = keywordify(keywords)
|
658
801
|
current_kws = kwattr_values(attribute_name)
|
@@ -661,50 +804,51 @@ module Nokogiri
|
|
661
804
|
self
|
662
805
|
end
|
663
806
|
|
664
|
-
#
|
665
|
-
#
|
807
|
+
# :call-seq:
|
808
|
+
# kwattr_append(attribute_name, keywords) → self
|
809
|
+
#
|
810
|
+
# Add keywords to a Node's keyword attribute, regardless of duplication. Compare with
|
811
|
+
# #kwattr_add.
|
666
812
|
#
|
667
|
-
# A "keyword attribute" is a node attribute that contains a set
|
668
|
-
#
|
669
|
-
#
|
670
|
-
#
|
671
|
-
# [`rel`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
|
813
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
814
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
815
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
816
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
672
817
|
#
|
673
|
-
#
|
674
|
-
# @see #kwattr_values
|
675
|
-
# @see #kwattr_add
|
676
|
-
# @see #kwattr_remove
|
818
|
+
# See also #append_class, #kwattr_values, #kwattr_add, #kwattr_remove
|
677
819
|
#
|
678
|
-
#
|
820
|
+
# [Parameters]
|
821
|
+
# - +attribute_name+ (String) The name of the keyword attribute to be modified.
|
822
|
+
# - +keywords+ (String, Array<String>)
|
823
|
+
# Keywords to be added to the attribute named +attribute_name+. May be a string containing
|
824
|
+
# whitespace-delimited values, or an Array of String values. All values passed in will be
|
825
|
+
# appended to the named attribute even if they are already present in the attribute. If the
|
826
|
+
# named attribute does not exist, it is created.
|
679
827
|
#
|
680
|
-
#
|
828
|
+
# [Returns] +self+ (Node) for ease of chaining method calls.
|
681
829
|
#
|
682
|
-
#
|
683
|
-
# +attribute_name+. May be a string containing
|
684
|
-
# whitespace-delimited values, or an Array of String
|
685
|
-
# values. All values passed in will be appended to the named
|
686
|
-
# attribute even if they are already present in the
|
687
|
-
# attribute. If the named attribute does not exist, it is
|
688
|
-
# created.
|
830
|
+
# *Example:* Append "nofollow" to the +rel+ attribute.
|
689
831
|
#
|
690
|
-
#
|
832
|
+
# Note that duplicates are added.
|
691
833
|
#
|
692
|
-
# @example Append "nofollow" to the +rel+ attribute.
|
693
834
|
# node # => <a></a>
|
694
835
|
# node.kwattr_append("rel", "nofollow") # => <a rel="nofollow"></a>
|
695
|
-
# node.kwattr_append("rel", "nofollow") # => <a rel="nofollow nofollow"></a>
|
836
|
+
# node.kwattr_append("rel", "nofollow") # => <a rel="nofollow nofollow"></a>
|
837
|
+
#
|
838
|
+
# *Example:* Append "nofollow" and "noreferrer" to the +rel+ attribute, via a String argument.
|
839
|
+
#
|
840
|
+
# Note that "nofollow" is appended even though it is already present.
|
696
841
|
#
|
697
|
-
# @example Append "nofollow" and "noreferrer" to the +rel+ attribute, via a String argument.
|
698
842
|
# node # => <a rel="nofollow"></a>
|
699
843
|
# node.kwattr_append("rel", "nofollow noreferrer") # => <a rel="nofollow nofollow noreferrer"></a>
|
700
|
-
# # Note that "nofollow" is appended even though it is already present.
|
701
844
|
#
|
702
|
-
#
|
845
|
+
#
|
846
|
+
# *Example:* Append "nofollow" and "noreferrer" to the +rel+ attribute, via an Array argument.
|
847
|
+
#
|
703
848
|
# node # => <a></a>
|
704
849
|
# node.kwattr_append("rel", ["nofollow", "noreferrer"]) # => <a rel="nofollow noreferrer"></a>
|
705
850
|
#
|
706
|
-
#
|
707
|
-
#
|
851
|
+
# Since v1.11.0
|
708
852
|
def kwattr_append(attribute_name, keywords)
|
709
853
|
keywords = keywordify(keywords)
|
710
854
|
current_kws = kwattr_values(attribute_name)
|
@@ -713,44 +857,41 @@ module Nokogiri
|
|
713
857
|
self
|
714
858
|
end
|
715
859
|
|
716
|
-
#
|
717
|
-
# keywords
|
718
|
-
#
|
860
|
+
# :call-seq:
|
861
|
+
# kwattr_remove(attribute_name, keywords) → self
|
862
|
+
#
|
863
|
+
# Remove keywords from a keyword attribute. Any matching keywords that exist in the named
|
864
|
+
# attribute are removed, including any multiple entries.
|
719
865
|
#
|
720
|
-
# If no keywords remain after this operation, or if +keywords+
|
721
|
-
#
|
866
|
+
# If no keywords remain after this operation, or if +keywords+ is +nil+, the attribute is
|
867
|
+
# deleted from the node.
|
722
868
|
#
|
723
|
-
# A "keyword attribute" is a node attribute that contains a set
|
724
|
-
#
|
725
|
-
#
|
726
|
-
#
|
727
|
-
# [`rel`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
|
869
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
870
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
871
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
872
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
728
873
|
#
|
729
|
-
#
|
730
|
-
# @see #kwattr_values
|
731
|
-
# @see #kwattr_add
|
732
|
-
# @see #kwattr_append
|
874
|
+
# See also #remove_class, #kwattr_values, #kwattr_add, #kwattr_append
|
733
875
|
#
|
734
|
-
#
|
876
|
+
# [Parameters]
|
877
|
+
# - +attribute_name+ (String) The name of the keyword attribute to be modified.
|
878
|
+
# - +keywords+ (String, Array<String>)
|
879
|
+
# Keywords to be removed from the attribute named +attribute_name+. May be a string
|
880
|
+
# containing whitespace-delimited values, or an Array of String values. Any keywords present
|
881
|
+
# in the named attribute will be removed. If no keywords remain, or if +keywords+ is nil,
|
882
|
+
# the attribute is deleted.
|
735
883
|
#
|
736
|
-
#
|
884
|
+
# [Returns] +self+ (Node) for ease of chaining method calls.
|
737
885
|
#
|
738
|
-
#
|
739
|
-
# +attribute_name+. May be a string containing
|
740
|
-
# whitespace-delimited values, or an Array of String
|
741
|
-
# values. Any keywords present in the named attribute will be
|
742
|
-
# removed. If no keywords remain, or if +keywords+ is nil, the
|
743
|
-
# attribute is deleted.
|
886
|
+
# *Example:*
|
744
887
|
#
|
745
|
-
#
|
888
|
+
# Note that the +rel+ attribute is deleted when empty.
|
746
889
|
#
|
747
|
-
# @example
|
748
890
|
# node # => <a rel="nofollow noreferrer">link</a>
|
749
891
|
# node.kwattr_remove("rel", "nofollow") # => <a rel="noreferrer">link</a>
|
750
|
-
# node.kwattr_remove("rel", "noreferrer") # => <a>link</a>
|
751
|
-
#
|
752
|
-
# @since v1.11.0
|
892
|
+
# node.kwattr_remove("rel", "noreferrer") # => <a>link</a>
|
753
893
|
#
|
894
|
+
# Since v1.11.0
|
754
895
|
def kwattr_remove(attribute_name, keywords)
|
755
896
|
if keywords.nil?
|
756
897
|
remove_attribute(attribute_name)
|
@@ -768,13 +909,13 @@ module Nokogiri
|
|
768
909
|
self
|
769
910
|
end
|
770
911
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
912
|
+
alias_method :delete, :remove_attribute
|
913
|
+
alias_method :get_attribute, :[]
|
914
|
+
alias_method :attr, :[]
|
915
|
+
alias_method :set_attribute, :[]=
|
916
|
+
alias_method :has_attribute?, :key?
|
776
917
|
|
777
|
-
#
|
918
|
+
# :section:
|
778
919
|
|
779
920
|
###
|
780
921
|
# Returns true if this Node matches +selector+
|
@@ -786,8 +927,7 @@ module Nokogiri
|
|
786
927
|
# Create a DocumentFragment containing +tags+ that is relative to _this_
|
787
928
|
# context node.
|
788
929
|
def fragment(tags)
|
789
|
-
|
790
|
-
type::DocumentFragment.new(document, tags, self)
|
930
|
+
document.related_class("DocumentFragment").new(document, tags, self)
|
791
931
|
end
|
792
932
|
|
793
933
|
###
|
@@ -805,19 +945,18 @@ module Nokogiri
|
|
805
945
|
end
|
806
946
|
|
807
947
|
options ||= (document.html? ? ParseOptions::DEFAULT_HTML : ParseOptions::DEFAULT_XML)
|
808
|
-
if Integer === options
|
809
|
-
options = Nokogiri::XML::ParseOptions.new(options)
|
810
|
-
end
|
811
|
-
# Give the options to the user
|
948
|
+
options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
|
812
949
|
yield options if block_given?
|
813
950
|
|
814
|
-
contents = string_or_io.respond_to?(:read)
|
815
|
-
string_or_io.read
|
951
|
+
contents = if string_or_io.respond_to?(:read)
|
952
|
+
string_or_io.read
|
953
|
+
else
|
816
954
|
string_or_io
|
955
|
+
end
|
817
956
|
|
818
957
|
return Nokogiri::XML::NodeSet.new(document) if contents.empty?
|
819
958
|
|
820
|
-
# libxml2 does not obey the
|
959
|
+
# libxml2 does not obey the +recover+ option after encountering errors during +in_context+
|
821
960
|
# parsing, and so this horrible hack is here to try to emulate recovery behavior.
|
822
961
|
#
|
823
962
|
# Unfortunately, this means we're no longer parsing "in context" and so namespaces that
|
@@ -827,16 +966,16 @@ module Nokogiri
|
|
827
966
|
#
|
828
967
|
# I think preferable behavior would be to either:
|
829
968
|
#
|
830
|
-
# a. add an error noting that we "fell back" and pointing the user to turning off the
|
969
|
+
# a. add an error noting that we "fell back" and pointing the user to turning off the +recover+ option
|
831
970
|
# b. don't recover, but raise a sensible exception
|
832
971
|
#
|
833
972
|
# For context and background: https://github.com/sparklemotion/nokogiri/issues/313
|
834
973
|
# FIXME bug report: https://github.com/sparklemotion/nokogiri/issues/2092
|
835
974
|
error_count = document.errors.length
|
836
975
|
node_set = in_context(contents, options.to_i)
|
837
|
-
if
|
976
|
+
if node_set.empty? && (document.errors.length > error_count)
|
838
977
|
if options.recover?
|
839
|
-
fragment =
|
978
|
+
fragment = document.related_class("DocumentFragment").parse(contents)
|
840
979
|
node_set = fragment.children
|
841
980
|
else
|
842
981
|
raise document.errors[error_count]
|
@@ -845,20 +984,42 @@ module Nokogiri
|
|
845
984
|
node_set
|
846
985
|
end
|
847
986
|
|
848
|
-
|
849
|
-
#
|
850
|
-
#
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
854
|
-
#
|
855
|
-
#
|
856
|
-
#
|
857
|
-
#
|
858
|
-
#
|
859
|
-
#
|
860
|
-
#
|
861
|
-
#
|
987
|
+
# :call-seq:
|
988
|
+
# namespaces() → Hash<String(Namespace#prefix) ⇒ String(Namespace#href)>
|
989
|
+
#
|
990
|
+
# Fetch all the namespaces on this node and its ancestors.
|
991
|
+
#
|
992
|
+
# Note that the keys in this hash XML attributes that would be used to define this namespace,
|
993
|
+
# such as "xmlns:prefix", not just the prefix.
|
994
|
+
#
|
995
|
+
# The default namespace for this node will be included with key "xmlns".
|
996
|
+
#
|
997
|
+
# See also #namespace_scopes
|
998
|
+
#
|
999
|
+
# [Returns]
|
1000
|
+
# Hash containing all the namespaces on this node and its ancestors. The hash keys are the
|
1001
|
+
# namespace prefix, and the hash value for each key is the namespace URI.
|
1002
|
+
#
|
1003
|
+
# *Example:*
|
1004
|
+
#
|
1005
|
+
# doc = Nokogiri::XML(<<~EOF)
|
1006
|
+
# <root xmlns="http://example.com/root" xmlns:in_scope="http://example.com/in_scope">
|
1007
|
+
# <first/>
|
1008
|
+
# <second xmlns="http://example.com/child"/>
|
1009
|
+
# <third xmlns:foo="http://example.com/foo"/>
|
1010
|
+
# </root>
|
1011
|
+
# EOF
|
1012
|
+
# doc.at_xpath("//root:first", "root" => "http://example.com/root").namespaces
|
1013
|
+
# # => {"xmlns"=>"http://example.com/root",
|
1014
|
+
# # "xmlns:in_scope"=>"http://example.com/in_scope"}
|
1015
|
+
# doc.at_xpath("//child:second", "child" => "http://example.com/child").namespaces
|
1016
|
+
# # => {"xmlns"=>"http://example.com/child",
|
1017
|
+
# # "xmlns:in_scope"=>"http://example.com/in_scope"}
|
1018
|
+
# doc.at_xpath("//root:third", "root" => "http://example.com/root").namespaces
|
1019
|
+
# # => {"xmlns:foo"=>"http://example.com/foo",
|
1020
|
+
# # "xmlns"=>"http://example.com/root",
|
1021
|
+
# # "xmlns:in_scope"=>"http://example.com/in_scope"}
|
1022
|
+
#
|
862
1023
|
def namespaces
|
863
1024
|
namespace_scopes.each_with_object({}) do |ns, hash|
|
864
1025
|
prefix = ns.prefix
|
@@ -882,14 +1043,14 @@ module Nokogiri
|
|
882
1043
|
type == DOCUMENT_NODE
|
883
1044
|
end
|
884
1045
|
|
885
|
-
# Returns true if this is an HTML4::Document node
|
1046
|
+
# Returns true if this is an HTML4::Document or HTML5::Document node
|
886
1047
|
def html?
|
887
1048
|
type == HTML_DOCUMENT_NODE
|
888
1049
|
end
|
889
1050
|
|
890
1051
|
# Returns true if this is a Document
|
891
1052
|
def document?
|
892
|
-
is_a?
|
1053
|
+
is_a?(XML::Document)
|
893
1054
|
end
|
894
1055
|
|
895
1056
|
# Returns true if this is a ProcessingInstruction node
|
@@ -912,6 +1073,7 @@ module Nokogiri
|
|
912
1073
|
# nil on XML documents and on unknown tags.
|
913
1074
|
def description
|
914
1075
|
return nil if document.xml?
|
1076
|
+
|
915
1077
|
Nokogiri::HTML4::ElementDescription[name]
|
916
1078
|
end
|
917
1079
|
|
@@ -927,7 +1089,7 @@ module Nokogiri
|
|
927
1089
|
type == ELEMENT_NODE
|
928
1090
|
end
|
929
1091
|
|
930
|
-
|
1092
|
+
alias_method :elem?, :element?
|
931
1093
|
|
932
1094
|
###
|
933
1095
|
# Turn this node in to a string. If the document is HTML, this method
|
@@ -943,9 +1105,9 @@ module Nokogiri
|
|
943
1105
|
|
944
1106
|
# Get the path to this node as a CSS expression
|
945
1107
|
def css_path
|
946
|
-
path.split(
|
947
|
-
part.
|
948
|
-
|
1108
|
+
path.split(%r{/}).map do |part|
|
1109
|
+
part.empty? ? nil : part.gsub(/\[(\d+)\]/, ':nth-of-type(\1)')
|
1110
|
+
end.compact.join(" > ")
|
949
1111
|
end
|
950
1112
|
|
951
1113
|
###
|
@@ -958,7 +1120,8 @@ module Nokogiri
|
|
958
1120
|
parents = [parent]
|
959
1121
|
|
960
1122
|
while parents.last.respond_to?(:parent)
|
961
|
-
break unless ctx_parent = parents.last.parent
|
1123
|
+
break unless (ctx_parent = parents.last.parent)
|
1124
|
+
|
962
1125
|
parents << ctx_parent
|
963
1126
|
end
|
964
1127
|
|
@@ -967,16 +1130,16 @@ module Nokogiri
|
|
967
1130
|
root = parents.last
|
968
1131
|
search_results = root.search(selector)
|
969
1132
|
|
970
|
-
NodeSet.new(document, parents.find_all
|
1133
|
+
NodeSet.new(document, parents.find_all do |parent|
|
971
1134
|
search_results.include?(parent)
|
972
|
-
|
1135
|
+
end)
|
973
1136
|
end
|
974
1137
|
|
975
1138
|
####
|
976
1139
|
# Yields self and all children to +block+ recursively.
|
977
1140
|
def traverse(&block)
|
978
1141
|
children.each { |j| j.traverse(&block) }
|
979
|
-
|
1142
|
+
yield(self)
|
980
1143
|
end
|
981
1144
|
|
982
1145
|
###
|
@@ -990,6 +1153,7 @@ module Nokogiri
|
|
990
1153
|
def ==(other)
|
991
1154
|
return false unless other
|
992
1155
|
return false unless other.respond_to?(:pointer_id)
|
1156
|
+
|
993
1157
|
pointer_id == other.pointer_id
|
994
1158
|
end
|
995
1159
|
|
@@ -999,14 +1163,16 @@ module Nokogiri
|
|
999
1163
|
def <=>(other)
|
1000
1164
|
return nil unless other.is_a?(Nokogiri::XML::Node)
|
1001
1165
|
return nil unless document == other.document
|
1002
|
-
|
1166
|
+
|
1167
|
+
compare(other)
|
1003
1168
|
end
|
1004
1169
|
|
1005
|
-
#
|
1170
|
+
# :section: Serialization and Generating Output
|
1006
1171
|
|
1007
1172
|
###
|
1008
|
-
# Serialize Node using +options+.
|
1009
|
-
#
|
1173
|
+
# Serialize Node using +options+. Save options can also be set using a block.
|
1174
|
+
#
|
1175
|
+
# See also Nokogiri::XML::Node::SaveOptions and Node@Serialization+and+Generating+Output.
|
1010
1176
|
#
|
1011
1177
|
# These two statements are equivalent:
|
1012
1178
|
#
|
@@ -1019,18 +1185,22 @@ module Nokogiri
|
|
1019
1185
|
# end
|
1020
1186
|
#
|
1021
1187
|
def serialize(*args, &block)
|
1022
|
-
options = args.first.is_a?(Hash)
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1188
|
+
options = if args.first.is_a?(Hash)
|
1189
|
+
args.shift
|
1190
|
+
else
|
1191
|
+
{
|
1192
|
+
encoding: args[0],
|
1193
|
+
save_with: args[1],
|
1194
|
+
}
|
1195
|
+
end
|
1026
1196
|
|
1027
1197
|
encoding = options[:encoding] || document.encoding
|
1028
1198
|
options[:encoding] = encoding
|
1029
1199
|
|
1030
|
-
outstring =
|
1200
|
+
outstring = +""
|
1031
1201
|
outstring.force_encoding(Encoding.find(encoding || "utf-8"))
|
1032
1202
|
io = StringIO.new(outstring)
|
1033
|
-
write_to
|
1203
|
+
write_to(io, options, &block)
|
1034
1204
|
io.string
|
1035
1205
|
end
|
1036
1206
|
|
@@ -1042,7 +1212,7 @@ module Nokogiri
|
|
1042
1212
|
# See Node#write_to for a list of +options+. For formatted output,
|
1043
1213
|
# use Node#to_xhtml instead.
|
1044
1214
|
def to_html(options = {})
|
1045
|
-
to_format
|
1215
|
+
to_format(SaveOptions::DEFAULT_HTML, options)
|
1046
1216
|
end
|
1047
1217
|
|
1048
1218
|
###
|
@@ -1063,7 +1233,7 @@ module Nokogiri
|
|
1063
1233
|
#
|
1064
1234
|
# See Node#write_to for a list of +options+
|
1065
1235
|
def to_xhtml(options = {})
|
1066
|
-
to_format
|
1236
|
+
to_format(SaveOptions::DEFAULT_XHTML, options)
|
1067
1237
|
end
|
1068
1238
|
|
1069
1239
|
###
|
@@ -1111,7 +1281,7 @@ module Nokogiri
|
|
1111
1281
|
#
|
1112
1282
|
# See Node#write_to for a list of +options+
|
1113
1283
|
def write_html_to(io, options = {})
|
1114
|
-
write_format_to
|
1284
|
+
write_format_to(SaveOptions::DEFAULT_HTML, io, options)
|
1115
1285
|
end
|
1116
1286
|
|
1117
1287
|
###
|
@@ -1119,7 +1289,7 @@ module Nokogiri
|
|
1119
1289
|
#
|
1120
1290
|
# See Node#write_to for a list of +options+
|
1121
1291
|
def write_xhtml_to(io, options = {})
|
1122
|
-
write_format_to
|
1292
|
+
write_format_to(SaveOptions::DEFAULT_XHTML, io, options)
|
1123
1293
|
end
|
1124
1294
|
|
1125
1295
|
###
|
@@ -1130,7 +1300,7 @@ module Nokogiri
|
|
1130
1300
|
# See Node#write_to for a list of options
|
1131
1301
|
def write_xml_to(io, options = {})
|
1132
1302
|
options[:save_with] ||= SaveOptions::DEFAULT_XML
|
1133
|
-
write_to
|
1303
|
+
write_to(io, options)
|
1134
1304
|
end
|
1135
1305
|
|
1136
1306
|
def canonicalize(mode = XML::XML_C14N_1_0, inclusive_namespaces = nil, with_comments = false)
|
@@ -1141,7 +1311,7 @@ module Nokogiri
|
|
1141
1311
|
end
|
1142
1312
|
end
|
1143
1313
|
|
1144
|
-
#
|
1314
|
+
# :section:
|
1145
1315
|
|
1146
1316
|
protected
|
1147
1317
|
|
@@ -1159,9 +1329,9 @@ module Nokogiri
|
|
1159
1329
|
return data
|
1160
1330
|
end
|
1161
1331
|
|
1162
|
-
raise ArgumentError,
|
1163
|
-
Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
|
1164
|
-
(You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
|
1332
|
+
raise ArgumentError, <<~EOERR
|
1333
|
+
Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
|
1334
|
+
(You probably want to select a node from the Document with at() or search(), or create a new Node via Node.new().)
|
1165
1335
|
EOERR
|
1166
1336
|
end
|
1167
1337
|
|
@@ -1170,32 +1340,33 @@ Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
|
|
1170
1340
|
def keywordify(keywords)
|
1171
1341
|
case keywords
|
1172
1342
|
when Enumerable
|
1173
|
-
|
1343
|
+
keywords
|
1174
1344
|
when String
|
1175
|
-
|
1345
|
+
keywords.scan(/\S+/)
|
1176
1346
|
else
|
1177
|
-
raise ArgumentError
|
1347
|
+
raise ArgumentError,
|
1348
|
+
"Keyword attributes must be passed as either a String or an Enumerable, but received #{keywords.class}"
|
1178
1349
|
end
|
1179
1350
|
end
|
1180
1351
|
|
1181
1352
|
def add_sibling(next_or_previous, node_or_tags)
|
1182
1353
|
raise("Cannot add sibling to a node with no parent") unless parent
|
1183
1354
|
|
1184
|
-
impl =
|
1185
|
-
iter =
|
1355
|
+
impl = next_or_previous == :next ? :add_next_sibling_node : :add_previous_sibling_node
|
1356
|
+
iter = next_or_previous == :next ? :reverse_each : :each
|
1186
1357
|
|
1187
1358
|
node_or_tags = parent.coerce(node_or_tags)
|
1188
1359
|
if node_or_tags.is_a?(XML::NodeSet)
|
1189
1360
|
if text?
|
1190
|
-
pivot = Nokogiri::XML::Node.new
|
1191
|
-
send
|
1361
|
+
pivot = Nokogiri::XML::Node.new("dummy", document)
|
1362
|
+
send(impl, pivot)
|
1192
1363
|
else
|
1193
1364
|
pivot = self
|
1194
1365
|
end
|
1195
|
-
node_or_tags.send(iter) { |n| pivot.send
|
1366
|
+
node_or_tags.send(iter) { |n| pivot.send(impl, n) }
|
1196
1367
|
pivot.unlink if text?
|
1197
1368
|
else
|
1198
|
-
send
|
1369
|
+
send(impl, node_or_tags)
|
1199
1370
|
end
|
1200
1371
|
node_or_tags
|
1201
1372
|
end
|
@@ -1214,19 +1385,18 @@ Requires a Node, NodeSet or String argument, and cannot accept a #{data.class}.
|
|
1214
1385
|
return (io << dump_html) if USING_LIBXML_WITH_BROKEN_SERIALIZATION
|
1215
1386
|
|
1216
1387
|
options[:save_with] ||= save_option
|
1217
|
-
write_to
|
1388
|
+
write_to(io, options)
|
1218
1389
|
end
|
1219
1390
|
|
1220
1391
|
def inspect_attributes
|
1221
1392
|
[:name, :namespace, :attribute_nodes, :children]
|
1222
1393
|
end
|
1223
1394
|
|
1224
|
-
|
1225
|
-
IMPLIED_XPATH_CONTEXTS = [".//".freeze].freeze
|
1395
|
+
IMPLIED_XPATH_CONTEXTS = [".//"].freeze
|
1226
1396
|
|
1227
1397
|
def add_child_node_and_reparent_attrs(node)
|
1228
|
-
add_child_node
|
1229
|
-
node.attribute_nodes.find_all { |a| a.name
|
1398
|
+
add_child_node(node)
|
1399
|
+
node.attribute_nodes.find_all { |a| a.name.include?(":") }.each do |attr_node|
|
1230
1400
|
attr_node.remove
|
1231
1401
|
node[attr_node.name] = attr_node.value
|
1232
1402
|
end
|