Class: Nokolexbor::NodeSet
- Includes:
- Enumerable
- Defined in:
- lib/nokolexbor/node_set.rb,
ext/nokolexbor/nl_node_set.c
Constant Summary
Constants inherited from Node
Nokolexbor::Node::ATTRIBUTE_NODE, Nokolexbor::Node::CDATA_SECTION_NODE, Nokolexbor::Node::COMMENT_NODE, Nokolexbor::Node::DOCUMENT_FRAG_NODE, Nokolexbor::Node::DOCUMENT_NODE, Nokolexbor::Node::DOCUMENT_TYPE_NODE, Nokolexbor::Node::ELEMENT_NODE, Nokolexbor::Node::ENTITY_NODE, Nokolexbor::Node::ENTITY_REF_NODE, Nokolexbor::Node::LOOKS_LIKE_XPATH, Nokolexbor::Node::NOTATION_NODE, Nokolexbor::Node::PI_NODE, Nokolexbor::Node::TEXT_NODE
Instance Attribute Summary
Attributes inherited from Node
Class Method Summary collapse
-
.new(document, list = []) {|Document| ... } ⇒ Document
Create a NodeSet with
documentdefaulting tolist.
Instance Method Summary collapse
-
#&(other) ⇒ NodeSet
A new NodeSet with the common nodes only.
-
#-(other) ⇒ NodeSet
A new NodeSet with the nodes in this NodeSet that aren't in
other. -
#==(other) ⇒ Boolean
True if two NodeSets contain the same number of elements and each element is equal to the corresponding element in the other NodeSet.
- #[](*args) ⇒ Node, ... (also: #slice)
-
#add_class(name) ⇒ Object
Add the class attribute
nameto all containing nodes. -
#after(node) ⇒ Object
Insert
nodeafter the last Node in this NodeSet. -
#append_class(name) ⇒ Object
Append the class attribute
nameto all containing nodes. -
#at_css(selector) ⇒ Node?
Like #css, but returns the first match.
-
#attr(key, value = nil, &block) ⇒ NodeSet
(also: #set, #attribute)
Set attributes on each Node in the NodeSet, or get an attribute from the first Node in the NodeSet.
-
#before(node) ⇒ Object
Insert
nodebefore the first Node in this NodeSet. -
#children ⇒ NodeSet
A new NodeSet containing all the children of all the nodes in the NodeSet.
-
#content ⇒ String
(also: #text, #inner_text, #to_str)
Get the content of all contained Nodes.
-
#css(selector) ⇒ NodeSet
Search this object for CSS
rules. -
#delete(node) ⇒ Node?
Delete
nodefrom the NodeSet. -
#destroy ⇒ Object
Destroy all nodes in the NodeSet.
-
#each {|Node| ... } ⇒ Object
Iterate over each node.
-
#empty? ⇒ Boolean
True if this NodeSet is empty.
-
#first(n = nil) ⇒ Node+
Get the first
nelements of the NodeSet. -
#include?(node) ⇒ Boolean
True if any member of this NodeSet equals
node. -
#index(node = nil) ⇒ Integer
The index of the first node in this NodeSet that is equal to
nodeor meets the given block. -
#inner_html(*args) ⇒ String
Get the inner html of all contained Nodes.
- #inspect ⇒ Object
-
#last ⇒ Node?
Get the last element of the NodeSet.
-
#length ⇒ Integer
(also: #size)
Get the length of this NodeSet.
-
#nokogiri_css(*args) ⇒ NodeSet
Search this object for CSS
rules. -
#outer_html(*args) ⇒ String
(also: #to_s, #to_html, #serialize)
Convert this NodeSet to HTML.
-
#pop ⇒ Node?
The last element of this NodeSet and removes it.
-
#push(node) ⇒ NodeSet
(also: #<<)
Append
nodeto the NodeSet. -
#remove ⇒ Object
(also: #unlink)
Remove all nodes in this NodeSet.
-
#remove_attr(name) ⇒ Object
(also: #remove_attribute)
Remove the attributed named
namefrom all containing nodes. -
#remove_class(name = nil) ⇒ Object
Remove the class attribute
namefrom all containing nodes. -
#reverse ⇒ NodeSet
A new NodeSet containing all the nodes in the NodeSet in reverse order.
-
#shift ⇒ Node?
The first element of this NodeSet and removes it.
-
#to_a ⇒ Array<Node>
(also: #to_ary)
This list as an Array.
-
#wrap(node_or_tags) ⇒ NodeSet
Wrap all nodes of this NodeSet with
node_or_tags. -
#xpath(*args) ⇒ NodeSet
Search this node for XPath
paths. -
#|(other) ⇒ NodeSet
(also: #+)
A new set built by merging the
otherset, excluding duplicates.
Methods inherited from Node
#[]=, #add_child, #add_next_sibling, #add_previous_sibling, #add_sibling, #ancestors, #at, #at_css_impl, #at_xpath, #attribute_nodes, #attributes, #attrs, #cdata?, #child, #children=, #classes, #clone, #comment?, #content=, #css_impl, #css_path, #document?, #element?, #element_children, #first_element_child, #fragment, #fragment?, #key?, #keys, #kwattr_add, #kwattr_append, #kwattr_remove, #kwattr_values, #last_element_child, #matches?, #name, #next, #next_element, #node_type, #nokogiri_at_css, #parent, #parent=, #parse, #path, #pointer_id, #prepend_child, #previous, #previous_element, #processing_instruction?, #replace, #search, #source_location, #swap, #text?, #traverse, #value?, #values, #write_to
Class Method Details
.new(document, list = []) {|Document| ... } ⇒ Document
Create a NodeSet with document defaulting to list.
12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/nokolexbor/node_set.rb', line 12 def self.new(document, list = []) obj = allocate if document.is_a?(Document) || document.nil? obj.instance_variable_set(:@document, document) elsif document.is_a?(Node) obj.instance_variable_set(:@document, document.document) else raise ArgumentError, "Expected a Document or Node, got #{document.class}" end list.each { |x| obj << x } yield obj if block_given? obj end |
Instance Method Details
#&(other) ⇒ NodeSet
Returns A new NodeSet with the common nodes only.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'ext/nokolexbor/nl_node_set.c', line 306
static VALUE
nl_node_set_intersection(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cNokolexborNodeSet)) {
rb_raise(rb_eArgError, "Parameter must be a Nokolexbor::NodeSet");
}
lexbor_array_t *self_array = nl_rb_node_set_unwrap(self);
lexbor_array_t *other_array = nl_rb_node_set_unwrap(other);
lexbor_array_t *new_array = lexbor_array_create();
for (size_t i = 0; i < self_array->length; i++) {
for (size_t j = 0; j < other_array->length; j++) {
if (self_array->list[i] == other_array->list[j]) {
lexbor_array_push(new_array, self_array->list[i]);
break;
}
}
}
return nl_rb_node_set_create_with_data(new_array, nl_rb_document_get(self));
}
|
#-(other) ⇒ NodeSet
Returns A new NodeSet with the nodes in this NodeSet that aren't in other.
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'ext/nokolexbor/nl_node_set.c', line 333
static VALUE
nl_node_set_difference(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cNokolexborNodeSet)) {
rb_raise(rb_eArgError, "Parameter must be a Nokolexbor::NodeSet");
}
lexbor_array_t *self_array = nl_rb_node_set_unwrap(self);
lexbor_array_t *other_array = nl_rb_node_set_unwrap(other);
lexbor_array_t *new_array = lexbor_array_create();
for (size_t i = 0; i < self_array->length; i++) {
bool found = false;
for (size_t j = 0; j < other_array->length; j++) {
if (self_array->list[i] == other_array->list[j]) {
found = true;
break;
}
}
if (!found) {
lexbor_array_push(new_array, self_array->list[i]);
}
}
return nl_rb_node_set_create_with_data(new_array, nl_rb_document_get(self));
}
|
#==(other) ⇒ Boolean
Returns true if two NodeSets contain the same number of elements and each element is equal to the corresponding element in the other NodeSet.
148 149 150 151 152 153 154 155 156 |
# File 'lib/nokolexbor/node_set.rb', line 148 def ==(other) return false unless other.is_a?(NodeSet) return false unless length == other.length each_with_index do |node, i| return false unless node == other[i] end true end |
#[](index) ⇒ Node? #[](start, length) ⇒ NodeSet? #[](range) ⇒ NodeSet? Also known as: slice
The Nokolexbor::Node at index, or returns a Nokolexbor::NodeSet
containing nodes starting at start and continuing for length elements, or
returns a Nokolexbor::NodeSet containing nodes specified by range. Negative indices
count backward from the end of the node_set (-1 is the last node). Returns
nil if the index (or start) are out of range.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'ext/nokolexbor/nl_node_set.c', line 212
static VALUE
nl_node_set_slice(int argc, VALUE *argv, VALUE self)
{
VALUE arg;
long beg, len;
lexbor_array_t *array = nl_rb_node_set_unwrap(self);
if (argc == 2) {
beg = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
if (beg < 0) {
beg += array->length;
}
return nl_node_set_subseq(self, beg, len);
}
if (argc != 1) {
rb_scan_args(argc, argv, "11", NULL, NULL);
}
arg = argv[0];
if (FIXNUM_P(arg)) {
return nl_node_set_index_at(self, FIX2LONG(arg));
}
/* if arg is Range */
switch (rb_range_beg_len(arg, &beg, &len, array->length, 0)) {
case Qfalse:
break;
case Qnil:
return Qnil;
default:
return nl_node_set_subseq(self, beg, len);
}
return nl_node_set_index_at(self, NUM2LONG(arg));
}
|
#add_class(name) ⇒ Object
Add the class attribute name to all containing nodes.
191 192 193 194 195 196 |
# File 'lib/nokolexbor/node_set.rb', line 191 def add_class(name) each do |el| el.add_class(name) end self end |
#after(node) ⇒ Object
Insert node after the last Node in this NodeSet
69 70 71 |
# File 'lib/nokolexbor/node_set.rb', line 69 def after(node) last.after(node) end |
#append_class(name) ⇒ Object
Append the class attribute name to all containing nodes.
201 202 203 204 205 206 |
# File 'lib/nokolexbor/node_set.rb', line 201 def append_class(name) each do |el| el.append_class(name) end self end |
#at_css(selector) ⇒ Node?
Like #css, but returns the first match.
This method uses Lexbor as the selector engine. Its performance is much higher than Nokolexbor::Node#at_xpath or Nokolexbor::Node#nokogiri_at_css.
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
# File 'ext/nokolexbor/nl_node_set.c', line 414
static VALUE
nl_node_set_at_css(VALUE self, VALUE selector)
{
lexbor_array_t *array = lexbor_array_create();
lxb_dom_document_t *doc = nl_rb_document_unwrap(nl_rb_document_get(self));
lxb_status_t status = nl_node_set_find(self, selector, nl_node_at_css_callback, array);
if (status != LXB_STATUS_OK) {
lexbor_array_destroy(array, true);
nl_raise_lexbor_error(status);
}
if (array->length == 0) {
lexbor_array_destroy(array, true);
return Qnil;
}
nl_sort_nodes_if_necessary(selector, doc, array);
VALUE ret = nl_rb_node_create(array->list[0], nl_rb_document_get(self));
lexbor_array_destroy(array, true);
return ret;
}
|
#attr(key, value = nil, &block) ⇒ NodeSet Also known as: set, attribute
Set attributes on each Node in the NodeSet, or get an attribute from the first Node in the NodeSet.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/nokolexbor/node_set.rb', line 239 def attr(key, value = nil, &block) unless key.is_a?(Hash) || (key && (value || block)) return first&.attribute(key) end hash = key.is_a?(Hash) ? key : { key => value } hash.each do |k, v| each do |node| node[k] = v || yield(node) end end self end |
#before(node) ⇒ Object
Insert node before the first Node in this NodeSet
64 65 66 |
# File 'lib/nokolexbor/node_set.rb', line 64 def before(node) first.before(node) end |
#children ⇒ NodeSet
Returns A new NodeSet containing all the children of all the nodes in the NodeSet.
160 161 162 163 164 165 166 |
# File 'lib/nokolexbor/node_set.rb', line 160 def children node_set = NodeSet.new(@document) each do |node| node.children.each { |n| node_set.push(n) } end node_set end |
#content ⇒ String Also known as: text, inner_text, to_str
Get the content of all contained Nodes.
86 87 88 |
# File 'lib/nokolexbor/node_set.rb', line 86 def content self.map(&:content).join end |
#css(selector) ⇒ NodeSet
Search this object for CSS rules. rules must be one or more CSS
selectors.
This method uses Lexbor as the selector engine. Its performance is much higher than #xpath or #nokogiri_css.
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'ext/nokolexbor/nl_node_set.c', line 444
static VALUE
nl_node_set_css(VALUE self, VALUE selector)
{
lexbor_array_t *array = lexbor_array_create();
lxb_dom_document_t *doc = nl_rb_document_unwrap(nl_rb_document_get(self));
lxb_status_t status = nl_node_set_find(self, selector, nl_node_css_callback, array);
if (status != LXB_STATUS_OK) {
lexbor_array_destroy(array, true);
nl_raise_lexbor_error(status);
}
nl_sort_nodes_if_necessary(selector, doc, array);
return nl_rb_node_set_create_with_data(array, nl_rb_document_get(self));
}
|
#delete(node) ⇒ Node?
Delete node from the NodeSet.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'ext/nokolexbor/nl_node_set.c', line 111
static VALUE
nl_node_set_delete(VALUE self, VALUE rb_node)
{
lexbor_array_t *array = nl_rb_node_set_unwrap(self);
lxb_dom_node_t *node = nl_rb_node_unwrap(rb_node);
size_t i;
for (i = 0; i < array->length; i++)
if (array->list[i] == node) {
break;
}
if (i >= array->length) {
// not found
return Qnil;
}
lexbor_array_delete(array, i, 1);
return rb_node;
}
|
#destroy ⇒ Object
Destroy all nodes in the NodeSet.
125 126 127 |
# File 'lib/nokolexbor/node_set.rb', line 125 def destroy self.each(&:destroy) end |
#each {|Node| ... } ⇒ Object
Iterate over each node.
29 30 31 32 33 34 35 36 |
# File 'lib/nokolexbor/node_set.rb', line 29 def each return to_enum unless block_given? 0.upto(length - 1) do |x| yield self[x] end self end |
#empty? ⇒ Boolean
Returns true if this NodeSet is empty.
59 60 61 |
# File 'lib/nokolexbor/node_set.rb', line 59 def empty? length == 0 end |
#first(n = nil) ⇒ Node+
Get the first n elements of the NodeSet.
43 44 45 46 47 48 49 |
# File 'lib/nokolexbor/node_set.rb', line 43 def first(n = nil) return self[0] unless n list = [] [n, length].min.times { |i| list << self[i] } list end |
#include?(node) ⇒ Boolean
Returns true if any member of this NodeSet equals node.
137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'ext/nokolexbor/nl_node_set.c', line 137
static VALUE
nl_node_set_is_include(VALUE self, VALUE rb_node)
{
lexbor_array_t *array = nl_rb_node_set_unwrap(self);
lxb_dom_node_t *node = nl_rb_node_unwrap(rb_node);
for (size_t i = 0; i < array->length; i++)
if (array->list[i] == node) {
return Qtrue;
}
return Qfalse;
}
|
#index(node = nil) ⇒ Integer
Returns The index of the first node in this NodeSet that is equal to node or meets the given block. Returns nil if no match is found.
74 75 76 77 78 79 80 81 |
# File 'lib/nokolexbor/node_set.rb', line 74 def index(node = nil) if node each_with_index { |member, j| return j if member == node } elsif block_given? each_with_index { |member, j| return j if yield(member) } end nil end |
#inner_html(*args) ⇒ String
Get the inner html of all contained Nodes.
97 98 99 |
# File 'lib/nokolexbor/node_set.rb', line 97 def inner_html(*args) self.map { |n| n.inner_html(*args) }.join end |
#inspect ⇒ Object
284 285 286 |
# File 'lib/nokolexbor/node_set.rb', line 284 def inspect "[#{map(&:inspect).join(', ')}]" end |
#last ⇒ Node?
Get the last element of the NodeSet.
54 55 56 |
# File 'lib/nokolexbor/node_set.rb', line 54 def last self[-1] end |
#length ⇒ Integer Also known as: size
Get the length of this NodeSet.
71 72 73 74 75 |
# File 'ext/nokolexbor/nl_node_set.c', line 71
static VALUE
nl_node_set_length(VALUE self)
{
return INT2NUM(nl_rb_node_set_unwrap(self)->length);
}
|
#nokogiri_css(*args) ⇒ NodeSet
Search this object for CSS rules. rules must be one or more CSS
selectors. It supports a mixed syntax of CSS selectors and XPath.
This method uses libxml2 as the selector engine. It works the same way as Nokogiri::Node#css.
271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/nokolexbor/node_set.rb', line 271 def nokogiri_css(*args) rules, handler, ns, _ = extract_params(args) paths = css_rules_to_xpath(rules, ns) NodeSet.new(@document) do |set| each do |node| node.send(:xpath_internal, node, paths, handler, ns, nil).each do |inner_node| set << inner_node end end end end |
#outer_html(*args) ⇒ String Also known as: to_s, to_html, serialize
Convert this NodeSet to HTML.
104 105 106 |
# File 'lib/nokolexbor/node_set.rb', line 104 def outer_html(*args) self.map { |n| n.outer_html(*args) }.join end |
#pop ⇒ Node?
Returns The last element of this NodeSet and removes it. Returns
nil if the set is empty.
131 132 133 134 135 |
# File 'lib/nokolexbor/node_set.rb', line 131 def pop return nil if length == 0 delete(last) end |
#push(node) ⇒ NodeSet Also known as: <<
Append node to the NodeSet.
87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'ext/nokolexbor/nl_node_set.c', line 87
static VALUE
nl_node_set_push(VALUE self, VALUE rb_node)
{
lexbor_array_t *array = nl_rb_node_set_unwrap(self);
lxb_dom_node_t *node = nl_rb_node_unwrap(rb_node);
lxb_status_t status = lexbor_array_push_unique(array, node);
if (status != LXB_STATUS_OK && status != LXB_STATUS_STOPPED) {
nl_raise_lexbor_error(status);
}
return self;
}
|
#remove ⇒ Object Also known as: unlink
Remove all nodes in this NodeSet.
115 116 117 |
# File 'lib/nokolexbor/node_set.rb', line 115 def remove self.each(&:remove) end |
#remove_attr(name) ⇒ Object Also known as: remove_attribute
Remove the attributed named name from all containing nodes.
221 222 223 224 |
# File 'lib/nokolexbor/node_set.rb', line 221 def remove_attr(name) each { |el| el.delete(name) } self end |
#remove_class(name = nil) ⇒ Object
Remove the class attribute name from all containing nodes.
211 212 213 214 215 216 |
# File 'lib/nokolexbor/node_set.rb', line 211 def remove_class(name = nil) each do |el| el.remove_class(name) end self end |
#reverse ⇒ NodeSet
Returns A new NodeSet containing all the nodes in the NodeSet in reverse order.
170 171 172 173 174 175 176 |
# File 'lib/nokolexbor/node_set.rb', line 170 def reverse node_set = NodeSet.new(@document) (length - 1).downto(0) do |x| node_set.push(self[x]) end node_set end |
#shift ⇒ Node?
Returns The first element of this NodeSet and removes it. Returns
nil if the set is empty.
139 140 141 142 143 |
# File 'lib/nokolexbor/node_set.rb', line 139 def shift return nil if length == 0 delete(first) end |
#to_a ⇒ Array<Node> Also known as: to_ary
Returns This list as an Array.
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'ext/nokolexbor/nl_node_set.c', line 254
static VALUE
nl_node_set_to_array(VALUE self)
{
lexbor_array_t *array = nl_rb_node_set_unwrap(self);
VALUE list = rb_ary_new2(array->length);
VALUE doc = nl_rb_document_get(self);
for (size_t i = 0; i < array->length; i++) {
lxb_dom_node_t *node = (lxb_dom_node_t *)array->list[i];
VALUE rb_node = nl_rb_node_create(node, doc);
rb_ary_push(list, rb_node);
}
return list;
}
|
#wrap(node_or_tags) ⇒ NodeSet
Wrap all nodes of this NodeSet with node_or_tags.
183 184 185 186 |
# File 'lib/nokolexbor/node_set.rb', line 183 def wrap() map { |node| node.wrap() } self end |
#xpath(*args) ⇒ NodeSet
Search this node for XPath paths. paths must be one or more XPath
queries.
It works the same way as Nokogiri::Node#xpath.
258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/nokolexbor/node_set.rb', line 258 def xpath(*args) paths, handler, ns, binds = extract_params(args) NodeSet.new(@document) do |set| each do |node| node.send(:xpath_internal, node, paths, handler, ns, binds).each do |inner_node| set << inner_node end end end end |
#|(other) ⇒ NodeSet Also known as: +
Returns A new set built by merging the other set, excluding duplicates.
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'ext/nokolexbor/nl_node_set.c', line 273
static VALUE
nl_node_set_union(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cNokolexborNodeSet)) {
rb_raise(rb_eArgError, "Parameter must be a Nokolexbor::NodeSet");
}
lexbor_array_t *self_array = nl_rb_node_set_unwrap(self);
lexbor_array_t *other_array = nl_rb_node_set_unwrap(other);
if (self_array->length + other_array->length == 0) {
return nl_rb_node_set_create_with_data(NULL, nl_rb_document_get(self));
}
lexbor_array_t *new_array = lexbor_array_create();
lxb_status_t status = lexbor_array_init(new_array, self_array->length + other_array->length);
if (status != LXB_STATUS_OK) {
nl_raise_lexbor_error(status);
}
memcpy(new_array->list, self_array->list, sizeof(lxb_dom_node_t *) * self_array->length);
new_array->length = self_array->length;
for (size_t i = 0; i < other_array->length; i++) {
lexbor_array_push_unique(new_array, other_array->list[i]);
}
return nl_rb_node_set_create_with_data(new_array, nl_rb_document_get(self));
}
|