class Nokogiri::XML::NodeSet
A NodeSet
is an Enumerable that contains a list of Nokogiri::XML::Node
objects.
Typically a NodeSet
is returned as a result of searching a Document
via Nokogiri::XML::Searchable#css
or Nokogiri::XML::Searchable#xpath
.
Note that the ‘#dup` and `#clone` methods perform shallow copies; these methods do not copy the Nodes contained in the NodeSet
(similar to how Array and other Enumerable classes work).
Attributes
Public Class Methods
Create a NodeSet
with document
defaulting to list
# File lib/nokogiri/xml/node_set.rb, line 22 def initialize(document, list = []) @document = document document.decorate(self) list.each { |x| self << x } yield self if block_given? end
Public Instance Methods
Set Intersection — Returns a new NodeSet
containing nodes common to the two NodeSets.
static VALUE intersection(VALUE rb_self, VALUE rb_other) { xmlNodeSetPtr c_self, c_other ; xmlNodeSetPtr intersection; if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); } TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); intersection = xmlXPathIntersection(c_self, c_other); return noko_xml_node_set_wrap(intersection, rb_iv_get(rb_self, "@document")); }
Difference - returns a new NodeSet
that is a copy of this NodeSet
, removing each item that also appears in node_set
static VALUE minus(VALUE rb_self, VALUE rb_other) { xmlNodeSetPtr c_self, c_other; xmlNodeSetPtr new; int j ; if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); } TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); new = xmlXPathNodeSetMerge(NULL, c_self); for (j = 0 ; j < c_other->nodeNr ; ++j) { xpath_node_set_del(new, c_other->nodeTab[j]); } return noko_xml_node_set_wrap(new, rb_iv_get(rb_self, "@document")); }
Equality – Two NodeSets are equal if the contain the same number of elements and if each element is equal to the corresponding element in the other NodeSet
# File lib/nokogiri/xml/node_set.rb, line 395 def ==(other) return false unless other.is_a?(Nokogiri::XML::NodeSet) return false unless length == other.length each_with_index do |node, i| return false unless node == other[i] end true end
Element
reference - returns the node at index
, or returns a NodeSet
containing nodes starting at start
and continuing for length
elements, or returns a 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.
static VALUE slice(int argc, VALUE *argv, VALUE rb_self) { VALUE arg ; long beg, len ; xmlNodeSetPtr c_self; TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); if (argc == 2) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); if (beg < 0) { beg += c_self->nodeNr ; } return subseq(rb_self, beg, len); } if (argc != 1) { rb_scan_args(argc, argv, "11", NULL, NULL); } arg = argv[0]; if (FIXNUM_P(arg)) { return index_at(rb_self, FIX2LONG(arg)); } /* if arg is Range */ switch (rb_range_beg_len(arg, &beg, &len, (long)c_self->nodeNr, 0)) { case Qfalse: break; case Qnil: return Qnil; default: return subseq(rb_self, beg, len); } return index_at(rb_self, NUM2LONG(arg)); }
Add the class attribute name
to all Node
objects in the NodeSet
.
See Nokogiri::XML::Node#add_class
for more information.
# File lib/nokogiri/xml/node_set.rb, line 141 def add_class(name) each do |el| el.add_class(name) end self end
Append the class attribute name
to all Node
objects in the NodeSet
.
See Nokogiri::XML::Node#append_class
for more information.
# File lib/nokogiri/xml/node_set.rb, line 153 def append_class(name) each do |el| el.append_class(name) end self end
Search this object for paths
, and return only the first result. paths
must be one or more XPath
or CSS
queries.
See Searchable#search
for more information.
Or, if passed an integer, index into the NodeSet:
node_set.at(3) # same as node_set[3]
Nokogiri::XML::Searchable#at
# File lib/nokogiri/xml/node_set.rb, line 121 def at(*args) if args.length == 1 && args.first.is_a?(Numeric) return self[args.first] end super end
Set attributes on each Node
in the NodeSet
, or get an attribute from the first Node
in the NodeSet
.
To get an attribute from the first Node
in a NodeSet:
node_set.attr("href") # => "https://www.nokogiri.org"
Note that an empty NodeSet
will return nil when #attr
is called as a getter.
To set an attribute on each node, key
can either be an attribute name, or a Hash of attribute names and values. When called as a setter, #attr
returns the NodeSet
.
If key
is an attribute name, then either value
or block
must be passed.
If key
is a Hash then attributes will be set for each key/value pair:
node_set.attr("href" => "https://www.nokogiri.org", "class" => "member")
If value
is passed, it will be used as the attribute value for all nodes:
node_set.attr("href", "https://www.nokogiri.org")
If block
is passed, it will be called on each Node
object in the NodeSet
and the return value used as the attribute value for that node:
node_set.attr("class") { |node| node.name }
# File lib/nokogiri/xml/node_set.rb, line 205 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
Search this node set for CSS
rules
. rules
must be one or more CSS
selectors. For example:
For more information see Nokogiri::XML::Searchable#css
# File lib/nokogiri/xml/node_set.rb, line 85 def css(*args) rules, handler, ns, _ = extract_params(args) paths = css_rules_to_xpath(rules, ns) inject(NodeSet.new(document)) do |set, node| set + xpath_internal(node, paths, handler, ns, nil) end end
Returns the members of this NodeSet
as an array, to use in pattern matching.
Since v1.14.0
# File lib/nokogiri/xml/node_set.rb, line 442 def deconstruct to_a end
Delete node
from the Nodeset, if it is a member. Returns the deleted node if found, otherwise returns nil.
static VALUE delete (VALUE rb_self, VALUE rb_node) { xmlNodeSetPtr c_self; xmlNodePtr node; Check_Node_Set_Node_Type(rb_node); TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); Noko_Node_Get_Struct(rb_node, xmlNode, node); if (xmlXPathNodeSetContains(c_self, node)) { xpath_node_set_del(c_self, node); return rb_node; } return Qnil ; }
Iterate over each node, yielding to block
# File lib/nokogiri/xml/node_set.rb, line 233 def each return to_enum unless block_given? 0.upto(length - 1) do |x| yield self[x] end self end
Is this NodeSet
empty?
# File lib/nokogiri/xml/node_set.rb, line 47 def empty? length == 0 end
Filter this list for nodes that match expr
# File lib/nokogiri/xml/node_set.rb, line 132 def filter(expr) find_all { |node| node.matches?(expr) } end
Get the first element of the NodeSet
.
# File lib/nokogiri/xml/node_set.rb, line 31 def first(n = nil) return self[0] unless n list = [] [n, length].min.times { |i| list << self[i] } list end
Returns true if any member of node set equals node
.
static VALUE include_eh(VALUE rb_self, VALUE rb_node) { xmlNodeSetPtr c_self; xmlNodePtr node; Check_Node_Set_Node_Type(rb_node); TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); Noko_Node_Get_Struct(rb_node, xmlNode, node); return (xmlXPathNodeSetContains(c_self, node) ? Qtrue : Qfalse); }
Returns the index of the first node in self that is == to node
or meets the given block. Returns nil if no match is found.
# File lib/nokogiri/xml/node_set.rb, line 53 def index(node = nil) if node warn("given block not used") if block_given? 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
Get the inner html of all contained Node
objects
# File lib/nokogiri/xml/node_set.rb, line 262 def inner_html(*args) collect { |j| j.inner_html(*args) }.join("") end
Get the inner text of all contained Node
objects
Note: This joins the text of all Node
objects in the NodeSet:
doc = Nokogiri::XML('<xml><a><d>foo</d><d>bar</d></a></xml>') doc.css('d').text # => "foobar"
Instead, if you want to return the text of all nodes in the NodeSet:
doc.css('d').map(&:text) # => ["foo", "bar"]
See Nokogiri::XML::Node#content
for more information.
# File lib/nokogiri/xml/node_set.rb, line 255 def inner_text collect(&:inner_text).join("") end
Return a nicely formatted string representation
# File lib/nokogiri/xml/node_set.rb, line 429 def inspect "[#{map(&:inspect).join(", ")}]" end
Get the last element of the NodeSet
.
# File lib/nokogiri/xml/node_set.rb, line 41 def last self[-1] end
Get the length of the node set
static VALUE length(VALUE rb_self) { xmlNodeSetPtr c_self; TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); return c_self ? INT2NUM(c_self->nodeNr) : INT2NUM(0); }
Removes the last element from set and returns it, or nil
if the set is empty
# File lib/nokogiri/xml/node_set.rb, line 376 def pop return if length == 0 delete(last) end
Append node
to the NodeSet
.
static VALUE push(VALUE rb_self, VALUE rb_node) { xmlNodeSetPtr c_self; xmlNodePtr node; Check_Node_Set_Node_Type(rb_node); TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); Noko_Node_Get_Struct(rb_node, xmlNode, node); xmlXPathNodeSetAdd(c_self, node); return rb_self; }
Remove the attributed named name
from all Node
objects in the NodeSet
# File lib/nokogiri/xml/node_set.rb, line 225 def remove_attr(name) each { |el| el.delete(name) } self end
Remove the class attribute name
from all Node
objects in the NodeSet
.
See Nokogiri::XML::Node#remove_class
for more information.
# File lib/nokogiri/xml/node_set.rb, line 165 def remove_class(name = nil) each do |el| el.remove_class(name) end self end
Returns the first element of the NodeSet
and removes it. Returns nil
if the set is empty.
# File lib/nokogiri/xml/node_set.rb, line 385 def shift return if length == 0 delete(first) end
Element
reference - returns the node at index
, or returns a NodeSet
containing nodes starting at start
and continuing for length
elements, or returns a 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.
Return this list as an Array
static VALUE to_array(VALUE rb_self) { xmlNodeSetPtr c_self ; VALUE list; int i; TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); list = rb_ary_new2(c_self->nodeNr); for (i = 0; i < c_self->nodeNr; i++) { VALUE elt = noko_xml_node_wrap_node_set_result(c_self->nodeTab[i], rb_self); rb_ary_push(list, elt); } return list; }
# File lib/nokogiri/xml/node_set.rb, line 343 def to_html(*args) if Nokogiri.jruby? options = args.first.is_a?(Hash) ? args.shift : {} options[:save_with] ||= Node::SaveOptions::DEFAULT_HTML args.insert(0, options) end if empty? encoding = (args.first.is_a?(Hash) ? args.first[:encoding] : nil) encoding ||= document.encoding encoding.nil? ? "" : "".encode(encoding) else map { |x| x.to_html(*args) }.join end end
Convert this NodeSet
to a string.
# File lib/nokogiri/xml/node_set.rb, line 337 def to_s map(&:to_s).join end
Convert this NodeSet
to XHTML
# File lib/nokogiri/xml/node_set.rb, line 360 def to_xhtml(*args) map { |x| x.to_xhtml(*args) }.join end
Unlink this NodeSet
and all Node
objects it contains from their current context.
static VALUE unlink_nodeset(VALUE rb_self) { xmlNodeSetPtr c_self; int j, nodeNr ; TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); nodeNr = c_self->nodeNr ; for (j = 0 ; j < nodeNr ; j++) { if (! NOKOGIRI_NAMESPACE_EH(c_self->nodeTab[j])) { VALUE node ; xmlNodePtr node_ptr; node = noko_xml_node_wrap(Qnil, c_self->nodeTab[j]); rb_funcall(node, rb_intern("unlink"), 0); /* modifies the C struct out from under the object */ Noko_Node_Get_Struct(node, xmlNode, node_ptr); c_self->nodeTab[j] = node_ptr ; } } return rb_self ; }
Wrap each member of this NodeSet
with the node parsed from markup
or a dup of the node
.
- Parameters
-
markup (String) Markup that is parsed, once per member of the
NodeSet
, and used as the wrapper. Each node’s parent, if it exists, is used as the context node for parsing; otherwise the associated document is used. If the parsed fragment has multiple roots, the first root node is used as the wrapper. -
node (
Nokogiri::XML::Node
) An element that is ‘#dup`ed and used as the wrapper.
- Returns
-
self
, to support chaining.
⚠ Note that if a String
is passed, the markup will be parsed once per node in the NodeSet
. You can avoid this overhead in cases where you know exactly the wrapper you wish to use by passing a Node
instead.
Also see Node#wrap
Example with a String
argument:
doc = Nokogiri::HTML5(<<~HTML) <html><body> <a>a</a> <a>b</a> <a>c</a> <a>d</a> </body></html> HTML doc.css("a").wrap("<div></div>") doc.to_html # => <html><head></head><body> # <div><a>a</a></div> # <div><a>b</a></div> # <div><a>c</a></div> # <div><a>d</a></div> # </body></html>
Example with a Node
argument
💡 Note that this is faster than the equivalent call passing a String
because it avoids having to reparse the wrapper markup for each node.
doc = Nokogiri::HTML5(<<~HTML) <html><body> <a>a</a> <a>b</a> <a>c</a> <a>d</a> </body></html> HTML doc.css("a").wrap(doc.create_element("div")) doc.to_html # => <html><head></head><body> # <div><a>a</a></div> # <div><a>b</a></div> # <div><a>c</a></div> # <div><a>d</a></div> # </body></html>
# File lib/nokogiri/xml/node_set.rb, line 330 def wrap(node_or_tags) map { |node| node.wrap(node_or_tags) } self end
Search this node set for XPath
paths
. paths
must be one or more XPath
queries.
For more information see Nokogiri::XML::Searchable#xpath
# File lib/nokogiri/xml/node_set.rb, line 101 def xpath(*args) paths, handler, ns, binds = extract_params(args) inject(NodeSet.new(document)) do |set, node| set + xpath_internal(node, paths, handler, ns, binds) end end
Returns a new set built by merging the set and the elements of the given set.
static VALUE rb_xml_node_set_union(VALUE rb_self, VALUE rb_other) { xmlNodeSetPtr c_self, c_other; xmlNodeSetPtr c_new_node_set; if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); } TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); c_new_node_set = xmlXPathNodeSetMerge(NULL, c_self); c_new_node_set = xmlXPathNodeSetMerge(c_new_node_set, c_other); return noko_xml_node_set_wrap(c_new_node_set, rb_iv_get(rb_self, "@document")); }