nokolexbor 0.3.3 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/nokolexbor/nl_attribute.c +201 -0
- data/ext/nokolexbor/nl_cdata.c +8 -0
- data/ext/nokolexbor/nl_comment.c +6 -0
- data/ext/nokolexbor/nl_document.c +53 -7
- data/ext/nokolexbor/nl_document_fragment.c +9 -0
- data/ext/nokolexbor/nl_error.c +21 -19
- data/ext/nokolexbor/nl_node.c +317 -48
- data/ext/nokolexbor/nl_node_set.c +56 -1
- data/ext/nokolexbor/nl_processing_instruction.c +6 -0
- data/ext/nokolexbor/nl_text.c +6 -0
- data/ext/nokolexbor/nokolexbor.c +1 -0
- data/ext/nokolexbor/nokolexbor.h +2 -0
- data/lib/nokolexbor/document.rb +52 -5
- data/lib/nokolexbor/document_fragment.rb +11 -0
- data/lib/nokolexbor/node.rb +370 -24
- data/lib/nokolexbor/node_set.rb +56 -0
- data/lib/nokolexbor/version.rb +1 -1
- data/lib/nokolexbor.rb +0 -1
- metadata +3 -25
- data/lib/nokolexbor/attribute.rb +0 -18
- data/vendor/lexbor/source/lexbor/encoding/base.h +0 -218
- data/vendor/lexbor/source/lexbor/encoding/big5.c +0 -42839
- data/vendor/lexbor/source/lexbor/encoding/config.cmake +0 -12
- data/vendor/lexbor/source/lexbor/encoding/const.h +0 -65
- data/vendor/lexbor/source/lexbor/encoding/decode.c +0 -3193
- data/vendor/lexbor/source/lexbor/encoding/decode.h +0 -370
- data/vendor/lexbor/source/lexbor/encoding/encode.c +0 -1931
- data/vendor/lexbor/source/lexbor/encoding/encode.h +0 -377
- data/vendor/lexbor/source/lexbor/encoding/encoding.c +0 -252
- data/vendor/lexbor/source/lexbor/encoding/encoding.h +0 -475
- data/vendor/lexbor/source/lexbor/encoding/euc_kr.c +0 -53883
- data/vendor/lexbor/source/lexbor/encoding/gb18030.c +0 -47905
- data/vendor/lexbor/source/lexbor/encoding/iso_2022_jp_katakana.c +0 -159
- data/vendor/lexbor/source/lexbor/encoding/jis0208.c +0 -22477
- data/vendor/lexbor/source/lexbor/encoding/jis0212.c +0 -15787
- data/vendor/lexbor/source/lexbor/encoding/multi.h +0 -53
- data/vendor/lexbor/source/lexbor/encoding/range.c +0 -71
- data/vendor/lexbor/source/lexbor/encoding/range.h +0 -34
- data/vendor/lexbor/source/lexbor/encoding/res.c +0 -222
- data/vendor/lexbor/source/lexbor/encoding/res.h +0 -34
- data/vendor/lexbor/source/lexbor/encoding/single.c +0 -13748
- data/vendor/lexbor/source/lexbor/encoding/single.h +0 -116
data/lib/nokolexbor/node.rb
CHANGED
@@ -17,38 +17,51 @@ module Nokolexbor
|
|
17
17
|
DOCUMENT_FRAG_NODE = 11
|
18
18
|
NOTATION_NODE = 12
|
19
19
|
|
20
|
+
# @return [Document] The associated {Document} of this node
|
20
21
|
attr_reader :document
|
21
22
|
|
22
23
|
LOOKS_LIKE_XPATH = %r{^(\./|/|\.\.|\.$)}
|
23
24
|
|
25
|
+
# @return true if this is a {Comment}
|
24
26
|
def comment?
|
25
27
|
type == COMMENT_NODE
|
26
28
|
end
|
27
29
|
|
30
|
+
# @return true if this is a {CDATA}
|
28
31
|
def cdata?
|
29
32
|
type == CDATA_SECTION_NODE
|
30
33
|
end
|
31
34
|
|
35
|
+
# @return true if this is a {ProcessingInstruction}
|
32
36
|
def processing_instruction?
|
33
37
|
type == PI_NODE
|
34
38
|
end
|
35
39
|
|
40
|
+
# @return true if this is a {Text}
|
36
41
|
def text?
|
37
42
|
type == TEXT_NODE
|
38
43
|
end
|
39
44
|
|
45
|
+
# @return true if this is a {DocumentFragment}
|
40
46
|
def fragment?
|
41
47
|
type == DOCUMENT_FRAG_NODE
|
42
48
|
end
|
43
49
|
|
50
|
+
# @return true if this is an {Element}
|
44
51
|
def element?
|
45
52
|
type == ELEMENT_NODE
|
46
53
|
end
|
47
54
|
|
55
|
+
# @return true if this is a {Document}
|
48
56
|
def document?
|
49
57
|
is_a?(Nokolexbor::Document)
|
50
58
|
end
|
51
59
|
|
60
|
+
# Get a list of ancestor Node of this Node
|
61
|
+
#
|
62
|
+
# @param [String, nil] selector The selector to match ancestors
|
63
|
+
#
|
64
|
+
# @return [NodeSet] A set of matched ancestor nodes
|
52
65
|
def ancestors(selector = nil)
|
53
66
|
return NodeSet.new(@document) unless respond_to?(:parent)
|
54
67
|
return NodeSet.new(@document) unless parent
|
@@ -71,10 +84,39 @@ module Nokolexbor
|
|
71
84
|
end)
|
72
85
|
end
|
73
86
|
|
87
|
+
# Wrap this Node with another node.
|
88
|
+
#
|
89
|
+
# @param node [String, Node] A string or a node
|
90
|
+
# - when {String}:
|
91
|
+
# The markup that is parsed and used as the wrapper. If the parsed
|
92
|
+
# fragment has multiple roots, the first root node is used as the wrapper.
|
93
|
+
# - when {Node}:
|
94
|
+
# An element that is cloned and used as the wrapper.
|
95
|
+
#
|
96
|
+
# @return [Node] +self+, to support chaining of calls.
|
97
|
+
#
|
98
|
+
# @see NodeSet#wrap
|
99
|
+
#
|
100
|
+
# @example with a {String} argument:
|
101
|
+
#
|
102
|
+
# doc = Nokolexbor::HTML('<body><a>123</a></body>')
|
103
|
+
# doc.at_css('a').wrap('<div></div>')
|
104
|
+
# doc.at_css('body').inner_html
|
105
|
+
# # => "<div><a>123</a></div>"
|
106
|
+
#
|
107
|
+
# @example with a {Node} argument:
|
108
|
+
#
|
109
|
+
# doc = Nokolexbor::HTML('<body><a>123</a></body>')
|
110
|
+
# doc.at_css('a').wrap(doc.create_element('div'))
|
111
|
+
# doc.at_css('body').inner_html
|
112
|
+
# # => "<div><a>123</a></div>"
|
113
|
+
#
|
74
114
|
def wrap(node)
|
75
115
|
case node
|
76
116
|
when String
|
77
117
|
new_parent = fragment(node).child
|
118
|
+
when DocumentFragment
|
119
|
+
new_parent = node.child
|
78
120
|
when Node
|
79
121
|
new_parent = node.dup
|
80
122
|
else
|
@@ -91,6 +133,13 @@ module Nokolexbor
|
|
91
133
|
self
|
92
134
|
end
|
93
135
|
|
136
|
+
# Insert +node_or_tags+ before this Node (as a sibling).
|
137
|
+
#
|
138
|
+
# @param node_or_tags [Node, DocumentFragment, NodeSet, String] The node to be added.
|
139
|
+
#
|
140
|
+
# @return [Node,NodeSet] The reparented {Node} (if +node_or_tags+ is a {Node}), or {NodeSet} (if +node_or_tags+ is a {DocumentFragment}, {NodeSet}, or {String}).
|
141
|
+
#
|
142
|
+
# @see #before
|
94
143
|
def add_previous_sibling(node_or_tags)
|
95
144
|
raise ArgumentError,
|
96
145
|
"A document may not have multiple root nodes." if parent&.document? && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
@@ -98,6 +147,13 @@ module Nokolexbor
|
|
98
147
|
add_sibling(:previous, node_or_tags)
|
99
148
|
end
|
100
149
|
|
150
|
+
# Insert +node_or_tags+ after this Node (as a sibling).
|
151
|
+
#
|
152
|
+
# @param node_or_tags [Node, DocumentFragment, NodeSet, String] The node to be added.
|
153
|
+
#
|
154
|
+
# @return [Node,NodeSet] The reparented {Node} (if +node_or_tags+ is a {Node}), or {NodeSet} (if +node_or_tags+ is a {DocumentFragment}, {NodeSet}, or {String}).
|
155
|
+
#
|
156
|
+
# @see #after
|
101
157
|
def add_next_sibling(node_or_tags)
|
102
158
|
raise ArgumentError,
|
103
159
|
"A document may not have multiple root nodes." if parent&.document? && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
|
@@ -105,11 +161,25 @@ module Nokolexbor
|
|
105
161
|
add_sibling(:next, node_or_tags)
|
106
162
|
end
|
107
163
|
|
164
|
+
# Insert +node_or_tags+ before this Node (as a sibling).
|
165
|
+
#
|
166
|
+
# @param node_or_tags [Node, DocumentFragment, NodeSet, String] The node to be added.
|
167
|
+
#
|
168
|
+
# @return [Node] +self+, to support chaining of calls.
|
169
|
+
#
|
170
|
+
# @see #add_previous_sibling
|
108
171
|
def before(node_or_tags)
|
109
172
|
add_previous_sibling(node_or_tags)
|
110
173
|
self
|
111
174
|
end
|
112
175
|
|
176
|
+
# Insert +node_or_tags+ after this Node (as a sibling).
|
177
|
+
#
|
178
|
+
# @param node_or_tags [Node, DocumentFragment, NodeSet, String] The node to be added.
|
179
|
+
#
|
180
|
+
# @return [Node] +self+, to support chaining of calls.
|
181
|
+
#
|
182
|
+
# @see #add_next_sibling
|
113
183
|
def after(node_or_tags)
|
114
184
|
add_next_sibling(node_or_tags)
|
115
185
|
self
|
@@ -120,11 +190,25 @@ module Nokolexbor
|
|
120
190
|
alias_method :next=, :add_next_sibling
|
121
191
|
alias_method :previous=, :add_previous_sibling
|
122
192
|
|
193
|
+
# Add +node_or_tags+ as a child of this Node.
|
194
|
+
#
|
195
|
+
# @param node_or_tags [Node, DocumentFragment, NodeSet, String] The node to be added.
|
196
|
+
#
|
197
|
+
# @return [Node] +self+, to support chaining of calls.
|
198
|
+
#
|
199
|
+
# @see #add_child
|
123
200
|
def <<(node_or_tags)
|
124
201
|
add_child(node_or_tags)
|
125
202
|
self
|
126
203
|
end
|
127
204
|
|
205
|
+
# Add +node+ as the first child of this Node.
|
206
|
+
#
|
207
|
+
# @param node [Node, DocumentFragment, NodeSet, String] The node to be added.
|
208
|
+
#
|
209
|
+
# @return [Node,NodeSet] The reparented {Node} (if +node+ is a {Node}), or {NodeSet} (if +node+ is a {DocumentFragment}, {NodeSet}, or {String}).
|
210
|
+
#
|
211
|
+
# @see #add_child
|
128
212
|
def prepend_child(node)
|
129
213
|
if (first = children.first)
|
130
214
|
# Mimic the error add_child would raise.
|
@@ -136,86 +220,175 @@ module Nokolexbor
|
|
136
220
|
end
|
137
221
|
end
|
138
222
|
|
223
|
+
# Traverse self and all children.
|
224
|
+
# @yield self and all children to +block+ recursively.
|
139
225
|
def traverse(&block)
|
140
226
|
children.each { |j| j.traverse(&block) }
|
141
227
|
yield(self)
|
142
228
|
end
|
143
229
|
|
230
|
+
# @param selector [String] The selector to match
|
231
|
+
#
|
232
|
+
# @return true if this Node matches +selector+
|
144
233
|
def matches?(selector)
|
145
234
|
ancestors.last.css(selector).any? { |node| node == self }
|
146
235
|
end
|
147
236
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
|
237
|
+
# Fetch this node's attributes.
|
238
|
+
#
|
239
|
+
# @return [Hash{String => Attribute}] Hash containing attributes belonging to +self+. The hash keys are String attribute names, and the hash values are {Nokolexbor::Attribute}.
|
153
240
|
def attributes
|
154
|
-
|
241
|
+
attribute_nodes.each_with_object({}) do |node, hash|
|
242
|
+
hash[node.name] = node
|
243
|
+
end
|
155
244
|
end
|
156
245
|
|
246
|
+
# Replace this Node with +node+.
|
247
|
+
#
|
248
|
+
# @param node [Node, DocumentFragment, NodeSet, String]
|
249
|
+
#
|
250
|
+
# @return [Node,NodeSet] The reparented {Node} (if +node+ is a {Node}), or {NodeSet} (if +node+ is a {DocumentFragment}, {NodeSet}, or {String}).
|
251
|
+
#
|
252
|
+
# @see #swap
|
157
253
|
def replace(node)
|
158
|
-
|
159
|
-
node.each { |n| add_sibling(:previous, n) }
|
160
|
-
else
|
161
|
-
add_sibling(:previous, node)
|
162
|
-
end
|
254
|
+
ret = add_sibling(:previous, node)
|
163
255
|
remove
|
256
|
+
ret
|
257
|
+
end
|
258
|
+
|
259
|
+
# Swap this Node for +node+.
|
260
|
+
#
|
261
|
+
# @param node [Node, DocumentFragment, NodeSet, String]
|
262
|
+
#
|
263
|
+
# @return [Node] +self+, to support chaining of calls.
|
264
|
+
#
|
265
|
+
# @see #replace
|
266
|
+
def swap(node)
|
267
|
+
replace(node)
|
268
|
+
self
|
164
269
|
end
|
165
270
|
|
271
|
+
# Set the content of this Node.
|
272
|
+
#
|
273
|
+
# @param node [Node, DocumentFragment, NodeSet, String] The node to be added.
|
274
|
+
#
|
275
|
+
# @see #inner_html=
|
166
276
|
def children=(node)
|
167
277
|
children.remove
|
168
|
-
|
169
|
-
node.each { |n| add_child(n) }
|
170
|
-
else
|
171
|
-
add_child(node)
|
172
|
-
end
|
278
|
+
add_child(node)
|
173
279
|
end
|
174
280
|
|
281
|
+
# Set the parent Node of this Node.
|
282
|
+
#
|
283
|
+
# @param parent_node [Node] The parent node.
|
175
284
|
def parent=(parent_node)
|
176
285
|
parent_node.add_child(self)
|
177
286
|
end
|
178
287
|
|
288
|
+
# Iterate over each attribute name and value pair of this Node.
|
289
|
+
#
|
290
|
+
# @yield [String,String] The name and value of the current attribute.
|
179
291
|
def each
|
180
292
|
attributes.each do |name, node|
|
181
293
|
yield [name, node.value]
|
182
294
|
end
|
183
295
|
end
|
184
296
|
|
297
|
+
# Create a {DocumentFragment} containing +tags+ that is relative to _this_
|
298
|
+
# context node.
|
299
|
+
#
|
300
|
+
# @return [DocumentFragment]
|
185
301
|
def fragment(tags)
|
186
302
|
Nokolexbor::DocumentFragment.new(document, tags, self)
|
187
303
|
end
|
188
304
|
|
189
305
|
alias_method :inner_html=, :children=
|
190
306
|
|
307
|
+
# Search this object for CSS +rules+. +rules+ must be one or more CSS
|
308
|
+
# selectors.
|
309
|
+
#
|
310
|
+
# This method uses Lexbor as the selector engine. Its performance is much higher than {#xpath} or {#nokogiri_css}.
|
311
|
+
#
|
312
|
+
# @example
|
313
|
+
# node.css('title')
|
314
|
+
# node.css('body h1.bold')
|
315
|
+
# node.css('div + p.green', 'div#one')
|
316
|
+
#
|
317
|
+
# @return [NodeSet] The matched set of Nodes.
|
318
|
+
#
|
319
|
+
# @see #xpath
|
320
|
+
# @see #nokogiri_css
|
191
321
|
def css(*args)
|
192
322
|
css_impl(args.join(', '))
|
193
323
|
end
|
194
324
|
|
325
|
+
# Like {#css}, but returns the first match.
|
326
|
+
#
|
327
|
+
# This method uses Lexbor as the selector engine. Its performance is much higher than {#at_xpath} or {#nokogiri_at_css}.
|
328
|
+
#
|
329
|
+
# @return [Node, nil] The first matched Node.
|
330
|
+
#
|
331
|
+
# @see #css
|
332
|
+
# @see #nokogiri_at_css
|
195
333
|
def at_css(*args)
|
196
334
|
at_css_impl(args.join(', '))
|
197
335
|
end
|
198
336
|
|
337
|
+
# Search this object for CSS +rules+. +rules+ must be one or more CSS
|
338
|
+
# selectors. It supports a mixed syntax of CSS selectors and XPath.
|
339
|
+
#
|
340
|
+
# This method uses libxml2 as the selector engine. It works the same way as {Nokogiri::Node#css}.
|
341
|
+
#
|
342
|
+
# @return [NodeSet] The matched set of Nodes.
|
343
|
+
#
|
344
|
+
# @see #css
|
199
345
|
def nokogiri_css(*args)
|
200
346
|
rules, handler, ns, _ = extract_params(args)
|
201
347
|
|
202
348
|
nokogiri_css_internal(self, rules, handler, ns)
|
203
349
|
end
|
204
350
|
|
351
|
+
# Like {#nokogiri_css}, but returns the first match.
|
352
|
+
#
|
353
|
+
# This method uses libxml2 as the selector engine. It works the same way as {Nokogiri::Node#at_css}.
|
354
|
+
#
|
355
|
+
# @return [Node, nil] The first matched Node.
|
356
|
+
#
|
357
|
+
# @see #nokogiri_at_css
|
358
|
+
# @see #at_css
|
205
359
|
def nokogiri_at_css(*args)
|
206
360
|
nokogiri_css(*args).first
|
207
361
|
end
|
208
362
|
|
363
|
+
# Search this node for XPath +paths+. +paths+ must be one or more XPath
|
364
|
+
# queries.
|
365
|
+
#
|
366
|
+
# It works the same way as {Nokogiri::Node#xpath}.
|
367
|
+
#
|
368
|
+
# @example
|
369
|
+
# node.xpath('.//title')
|
370
|
+
#
|
371
|
+
# @return [NodeSet] The matched set of Nodes.
|
209
372
|
def xpath(*args)
|
210
373
|
paths, handler, ns, binds = extract_params(args)
|
211
374
|
|
212
375
|
xpath_internal(self, paths, handler, ns, binds)
|
213
376
|
end
|
214
377
|
|
378
|
+
# Like {#xpath}, but returns the first match.
|
379
|
+
#
|
380
|
+
# It works the same way as {Nokogiri::Node#at_xpath}.
|
381
|
+
#
|
382
|
+
# @return [Node, nil] The first matched Node.
|
383
|
+
#
|
384
|
+
# @see #xpath
|
215
385
|
def at_xpath(*args)
|
216
386
|
xpath(*args).first
|
217
387
|
end
|
218
388
|
|
389
|
+
# Search this object for +paths+. +paths+ must be one or more XPath or CSS selectors.
|
390
|
+
#
|
391
|
+
# @return [NodeSet] The matched set of Nodes.
|
219
392
|
def search(*args)
|
220
393
|
paths, handler, ns, binds = extract_params(args)
|
221
394
|
|
@@ -228,6 +401,11 @@ module Nokolexbor
|
|
228
401
|
|
229
402
|
alias_method :/, :search
|
230
403
|
|
404
|
+
# Like {#search}, but returns the first match.
|
405
|
+
#
|
406
|
+
# @return [Node, nil] The first matched Node.
|
407
|
+
#
|
408
|
+
# @see #search
|
231
409
|
def at(*args)
|
232
410
|
paths, handler, ns, binds = extract_params(args)
|
233
411
|
|
@@ -240,26 +418,148 @@ module Nokolexbor
|
|
240
418
|
|
241
419
|
alias_method :%, :at
|
242
420
|
|
421
|
+
# Fetch CSS class names of a Node.
|
422
|
+
#
|
423
|
+
# This is a convenience function and is equivalent to:
|
424
|
+
#
|
425
|
+
# node.kwattr_values("class")
|
426
|
+
#
|
427
|
+
# @see #kwattr_values
|
428
|
+
# @see #add_class
|
429
|
+
# @see #append_class
|
430
|
+
# @see #remove_class
|
431
|
+
#
|
432
|
+
# @return [Array]
|
433
|
+
# The CSS classes present in the Node's "class" attribute. If the
|
434
|
+
# attribute is empty or non-existent, the return value is an empty array.
|
435
|
+
#
|
436
|
+
# @example
|
437
|
+
# node.classes # => ["section", "title", "header"]
|
243
438
|
def classes
|
244
439
|
kwattr_values("class")
|
245
440
|
end
|
246
441
|
|
442
|
+
# Ensure CSS classes are present on +self+. Any CSS classes in +names+ that already exist
|
443
|
+
# in the "class" attribute are _not_ added. Note that any existing duplicates in the
|
444
|
+
# "class" attribute are not removed. Compare with {#append_class}.
|
445
|
+
#
|
446
|
+
# This is a convenience function and is equivalent to:
|
447
|
+
#
|
448
|
+
# node.kwattr_add("class", names)
|
449
|
+
#
|
450
|
+
# @see #kwattr_add
|
451
|
+
# @see #classes
|
452
|
+
# @see #append_class
|
453
|
+
# @see #remove_class
|
454
|
+
#
|
455
|
+
# @param [String, Array<String>] names
|
456
|
+
# CSS class names to be added to the Node's "class" attribute. May be a string containing
|
457
|
+
# whitespace-delimited names, or an Array of String names. Any class names already present
|
458
|
+
# will not be added. Any class names not present will be added. If no "class" attribute
|
459
|
+
# exists, one is created.
|
460
|
+
#
|
461
|
+
# @return [Node] +self+, to support chaining of calls.
|
462
|
+
#
|
463
|
+
# @example
|
464
|
+
# node.add_class("section") # => <div class="section"></div>
|
465
|
+
# node.add_class("section") # => <div class="section"></div> # duplicate not added
|
466
|
+
# node.add_class("section header") # => <div class="section header"></div>
|
467
|
+
# node.add_class(["section", "header"]) # => <div class="section header"></div>
|
247
468
|
def add_class(names)
|
248
469
|
kwattr_add("class", names)
|
249
470
|
end
|
250
471
|
|
472
|
+
# Add CSS classes to +self+, regardless of duplication. Compare with {#add_class}.
|
473
|
+
#
|
474
|
+
# This is a convenience function and is equivalent to:
|
475
|
+
#
|
476
|
+
# node.kwattr_append("class", names)
|
477
|
+
#
|
478
|
+
# @see #kwattr_append
|
479
|
+
# @see #classes
|
480
|
+
# @see #add_class
|
481
|
+
# @see #remove_class
|
482
|
+
#
|
483
|
+
# @return [Node] +self+, to support chaining of calls.
|
251
484
|
def append_class(names)
|
252
485
|
kwattr_append("class", names)
|
253
486
|
end
|
254
487
|
|
488
|
+
# Remove CSS classes from this node. Any CSS class names in +css_classes+ that exist in
|
489
|
+
# this node's "class" attribute are removed, including any multiple entries.
|
490
|
+
#
|
491
|
+
# If no CSS classes remain after this operation, or if +css_classes+ is +nil+, the "class"
|
492
|
+
# attribute is deleted from the node.
|
493
|
+
#
|
494
|
+
# This is a convenience function and is equivalent to:
|
495
|
+
#
|
496
|
+
# node.kwattr_remove("class", css_classes)
|
497
|
+
#
|
498
|
+
# @see #kwattr_remove
|
499
|
+
# @see #classes
|
500
|
+
# @see #add_class
|
501
|
+
# @see #append_class
|
502
|
+
#
|
503
|
+
# @param names [String, Array<String>]
|
504
|
+
# CSS class names to be removed from the Node's
|
505
|
+
# "class" attribute. May be a string containing whitespace-delimited names, or an Array of
|
506
|
+
# String names. Any class names already present will be removed. If no CSS classes remain,
|
507
|
+
# the "class" attribute is deleted.
|
508
|
+
#
|
509
|
+
# @return [Node] +self+, to support chaining of calls.
|
510
|
+
#
|
511
|
+
# @example
|
512
|
+
# node.remove_class("section")
|
513
|
+
# node.remove_class(["section", "float"])
|
255
514
|
def remove_class(names = nil)
|
256
515
|
kwattr_remove("class", names)
|
257
516
|
end
|
258
517
|
|
518
|
+
# Fetch values from a keyword attribute of a Node.
|
519
|
+
#
|
520
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
521
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
522
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
523
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
524
|
+
#
|
525
|
+
# @see #kwattr_add
|
526
|
+
# @#kwattr_append
|
527
|
+
# @#kwattr_remove
|
528
|
+
#
|
529
|
+
# @param attribute_name [String]
|
530
|
+
# The name of the keyword attribute to be inspected.
|
531
|
+
#
|
532
|
+
# @return [Array<String>]
|
533
|
+
# The values present in the Node's +attribute_name+ attribute. If the
|
534
|
+
# attribute is empty or non-existent, the return value is an empty array.
|
259
535
|
def kwattr_values(attribute_name)
|
260
536
|
keywordify(attr(attribute_name) || [])
|
261
537
|
end
|
262
538
|
|
539
|
+
# Ensure that values are present in a keyword attribute.
|
540
|
+
#
|
541
|
+
# Any values in +keywords+ that already exist in the Node's attribute values are _not_
|
542
|
+
# added. Note that any existing duplicates in the attribute values are not removed. Compare
|
543
|
+
# with {#kwattr_append}.
|
544
|
+
#
|
545
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
546
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
547
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
548
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
549
|
+
#
|
550
|
+
# @see #add_class
|
551
|
+
# @see #kwattr_values
|
552
|
+
# @see #kwattr_append
|
553
|
+
# @see #kwattr_remove
|
554
|
+
#
|
555
|
+
# @param attribute_name [String] The name of the keyword attribute to be modified.
|
556
|
+
# @param keywords [String, Array<String>]
|
557
|
+
# Keywords to be added to the attribute named +attribute_name+. May be a string containing
|
558
|
+
# whitespace-delimited values, or an Array of String values. Any values already present will
|
559
|
+
# not be added. Any values not present will be added. If the named attribute does not exist,
|
560
|
+
# it is created.
|
561
|
+
#
|
562
|
+
# @return [Node] +self+, to support chaining of calls.
|
263
563
|
def kwattr_add(attribute_name, keywords)
|
264
564
|
keywords = keywordify(keywords)
|
265
565
|
current_kws = kwattr_values(attribute_name)
|
@@ -268,6 +568,27 @@ module Nokolexbor
|
|
268
568
|
self
|
269
569
|
end
|
270
570
|
|
571
|
+
# Add keywords to a Node's keyword attribute, regardless of duplication. Compare with
|
572
|
+
# {#kwattr_add}.
|
573
|
+
#
|
574
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
575
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
576
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
577
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
578
|
+
#
|
579
|
+
# @see #add_class
|
580
|
+
# @see #kwattr_values
|
581
|
+
# @see #kwattr_add
|
582
|
+
# @see #kwattr_remove
|
583
|
+
#
|
584
|
+
# @param attribute_name [String] The name of the keyword attribute to be modified.
|
585
|
+
# @param keywords [String, Array<String>]
|
586
|
+
# Keywords to be added to the attribute named +attribute_name+. May be a string containing
|
587
|
+
# whitespace-delimited values, or an Array of String values. Any values already present will
|
588
|
+
# not be added. Any values not present will be added. If the named attribute does not exist,
|
589
|
+
# it is created.
|
590
|
+
#
|
591
|
+
# @return [Node] +self+, to support chaining of calls.
|
271
592
|
def kwattr_append(attribute_name, keywords)
|
272
593
|
keywords = keywordify(keywords)
|
273
594
|
current_kws = kwattr_values(attribute_name)
|
@@ -276,6 +597,30 @@ module Nokolexbor
|
|
276
597
|
self
|
277
598
|
end
|
278
599
|
|
600
|
+
# Remove keywords from a keyword attribute. Any matching keywords that exist in the named
|
601
|
+
# attribute are removed, including any multiple entries.
|
602
|
+
#
|
603
|
+
# If no keywords remain after this operation, or if +keywords+ is +nil+, the attribute is
|
604
|
+
# deleted from the node.
|
605
|
+
#
|
606
|
+
# A "keyword attribute" is a node attribute that contains a set of space-delimited
|
607
|
+
# values. Perhaps the most familiar example of this is the HTML "class" attribute used to
|
608
|
+
# contain CSS classes. But other keyword attributes exist, for instance
|
609
|
+
# {the "rel" attribute}[https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel].
|
610
|
+
#
|
611
|
+
# @see #remove_class
|
612
|
+
# @see #kwattr_values
|
613
|
+
# @see #kwattr_add
|
614
|
+
# @see #kwattr_append
|
615
|
+
#
|
616
|
+
# @param attribute_name [String] The name of the keyword attribute to be modified.
|
617
|
+
# @param keywords [String, Array<String>]
|
618
|
+
# Keywords to be added to the attribute named +attribute_name+. May be a string containing
|
619
|
+
# whitespace-delimited values, or an Array of String values. Any values already present will
|
620
|
+
# not be added. Any values not present will be added. If the named attribute does not exist,
|
621
|
+
# it is created.
|
622
|
+
#
|
623
|
+
# @return [Node] +self+, to support chaining of calls.
|
279
624
|
def kwattr_remove(attribute_name, keywords)
|
280
625
|
if keywords.nil?
|
281
626
|
remove_attr(attribute_name)
|
@@ -293,6 +638,15 @@ module Nokolexbor
|
|
293
638
|
self
|
294
639
|
end
|
295
640
|
|
641
|
+
# Serialize Node and write to +io+.
|
642
|
+
def write_to(io, *options)
|
643
|
+
io.write(to_html(*options))
|
644
|
+
end
|
645
|
+
|
646
|
+
alias_method :write_html_to, :write_to
|
647
|
+
|
648
|
+
private
|
649
|
+
|
296
650
|
def keywordify(keywords)
|
297
651
|
case keywords
|
298
652
|
when Enumerable
|
@@ -305,14 +659,6 @@ module Nokolexbor
|
|
305
659
|
end
|
306
660
|
end
|
307
661
|
|
308
|
-
def write_to(io, *options)
|
309
|
-
io.write(to_html(*options))
|
310
|
-
end
|
311
|
-
|
312
|
-
alias_method :write_html_to, :write_to
|
313
|
-
|
314
|
-
private
|
315
|
-
|
316
662
|
def nokogiri_css_internal(node, rules, handler, ns)
|
317
663
|
xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
|
318
664
|
end
|