class Nokogiri::XML::NodeSet
A NodeSet
contains a list of Nokogiri::XML::Node
objects. Typically a NodeSet
is return as a result of searching a Document
via Nokogiri::XML::Searchable#css
or Nokogiri::XML::Searchable#xpath
Constants
- LOOKS_LIKE_XPATH
-
Included from Nokogiri::XML::Searchable
Regular expression used by
Searchable#search
to determine if a query string isCSS
orXPath
Attributes
Public Class Methods
Source
# File lib/nokogiri/xml/node_set.rb, line 20 def initialize(document, list = []) @document = document document.decorate(self) list.each { |x| self << x } yield self if block_given? end
Create a NodeSet
with document
defaulting to list
Public Instance Methods
Source
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")); }
Set Intersection — Returns a new NodeSet
containing nodes common to the two NodeSets.
Source
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")); }
Difference - returns a new NodeSet
that is a copy of this NodeSet
, removing each item that also appears in node_set
Source
# File lib/nokogiri/xml/node_set.rb, line 393 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
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
Source
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)); }
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.
Source
# File lib/nokogiri/xml/node_set.rb, line 139 def add_class(name) each do |el| el.add_class(name) end self end
Add the class attribute name
to all Node
objects in the NodeSet
.
See Nokogiri::XML::Node#add_class
for more information.
Source
Source
# File lib/nokogiri/xml/node_set.rb, line 151 def append_class(name) each do |el| el.append_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.
Source
# File lib/nokogiri/xml/node_set.rb, line 119 def at(*args) if args.length == 1 && args.first.is_a?(Numeric) return self[args.first] end super(*args) 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
Source
# File lib/nokogiri/xml/node_set.rb, line 203 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
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 }
Source
Source
Source
# File lib/nokogiri/xml/node_set.rb, line 83 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
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
Source
# File lib/nokogiri/xml/node_set.rb, line 440 def deconstruct to_a end
Returns the members of this NodeSet
as an array, to use in pattern matching.
Since v1.14.0
Source
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 ; }
Delete node
from the Nodeset, if it is a member. Returns the deleted node if found, otherwise returns nil.
Source
static VALUE duplicate(VALUE rb_self) { xmlNodeSetPtr c_self; xmlNodeSetPtr dupl; TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); dupl = xmlXPathNodeSetMerge(NULL, c_self); return noko_xml_node_set_wrap(dupl, rb_iv_get(rb_self, "@document")); }
Duplicate this NodeSet
. Note that the Nodes contained in the NodeSet
are not duplicated (similar to how Array and other Enumerable classes work).
Source
# File lib/nokogiri/xml/node_set.rb, line 231 def each return to_enum unless block_given? 0.upto(length - 1) do |x| yield self[x] end self end
Iterate over each node, yielding to block
Source
# File lib/nokogiri/xml/node_set.rb, line 45 def empty? length == 0 end
Is this NodeSet
empty?
Source
# File lib/nokogiri/xml/node_set.rb, line 130 def filter(expr) find_all { |node| node.matches?(expr) } end
Filter this list for nodes that match expr
Source
# File lib/nokogiri/xml/node_set.rb, line 29 def first(n = nil) return self[0] unless n list = [] [n, length].min.times { |i| list << self[i] } list end
Get the first element of the NodeSet
.
Source
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 true if any member of node set equals node
.
Source
# File lib/nokogiri/xml/node_set.rb, line 51 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
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.
Source
# File lib/nokogiri/xml/node_set.rb, line 260 def inner_html(*args) collect { |j| j.inner_html(*args) }.join("") end
Get the inner html of all contained Node
objects
Source
# File lib/nokogiri/xml/node_set.rb, line 253 def inner_text collect(&:inner_text).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.
Source
# File lib/nokogiri/xml/node_set.rb, line 427 def inspect "[#{map(&:inspect).join(", ")}]" end
Return a nicely formated string representation
Source
# File lib/nokogiri/xml/node_set.rb, line 39 def last self[-1] end
Get the last element of the NodeSet
.
Source
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); }
Get the length of the node set
Source
# File lib/nokogiri/xml/node_set.rb, line 374 def pop return if length == 0 delete(last) end
Removes the last element from set and returns it, or nil
if the set is empty
Source
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; }
Append node
to the NodeSet
.
Source
# File lib/nokogiri/xml/node_set.rb, line 223 def remove_attr(name) each { |el| el.delete(name) } self end
Remove the attributed named name
from all Node
objects in the NodeSet
Source
# File lib/nokogiri/xml/node_set.rb, line 163 def remove_class(name = nil) each do |el| el.remove_class(name) end self end
Remove the class attribute name
from all Node
objects in the NodeSet
.
See Nokogiri::XML::Node#remove_class
for more information.
Source
Source
# File lib/nokogiri/xml/node_set.rb, line 383 def shift return if length == 0 delete(first) end
Returns the first element of the NodeSet
and removes it. Returns nil
if the set is empty.
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.
Source
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; }
Return this list as an Array
Source
# File lib/nokogiri/xml/node_set.rb, line 341 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
Source
# File lib/nokogiri/xml/node_set.rb, line 335 def to_s map(&:to_s).join end
Convert this NodeSet
to a string.
Source
# File lib/nokogiri/xml/node_set.rb, line 358 def to_xhtml(*args) map { |x| x.to_xhtml(*args) }.join end
Convert this NodeSet
to XHTML
Source
Source
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 ; }
Unlink this NodeSet
and all Node
objects it contains from their current context.
Source
# File lib/nokogiri/xml/node_set.rb, line 328 def wrap(node_or_tags) map { |node| node.wrap(node_or_tags) } self end
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>
Source
# File lib/nokogiri/xml/node_set.rb, line 99 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
Search this node set for XPath
paths
. paths
must be one or more XPath
queries.
For more information see Nokogiri::XML::Searchable#xpath
Source
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")); }
Returns a new set built by merging the set and the elements of the given set.
Searching via XPath or CSS Queries
↑ topPublic Instance Methods
Source
# File lib/nokogiri/xml/searchable.rb, line 201 def >(selector) # rubocop:disable Naming/BinaryOperatorParameterName ns = document.root&.namespaces || {} xpath(CSS.xpath_for(selector, prefix: "./", ns: ns).first) end
Search this node’s immediate children using CSS
selector selector
Source
# File lib/nokogiri/xml/searchable.rb, line 143 def at_css(*args) css(*args).first end
Search this object for CSS
rules
, and return only the first match. rules
must be one or more CSS
selectors.
See Searchable#css
for more information.
Source
# File lib/nokogiri/xml/searchable.rb, line 193 def at_xpath(*args) xpath(*args).first end
Search this node for XPath
paths
, and return only the first match. paths
must be one or more XPath
queries.
See Searchable#xpath
for more information.
Source
# File lib/nokogiri/xml/searchable.rb, line 54 def search(*args) paths, handler, ns, binds = extract_params(args) xpaths = paths.map(&:to_s).map do |path| LOOKS_LIKE_XPATH.match?(path) ? path : xpath_query_from_css_rule(path, ns) end.flatten.uniq xpath(*(xpaths + [ns, handler, binds].compact)) end
Search this object for paths
. paths
must be one or more XPath
or CSS
queries:
node.search("div.employee", ".//title")
A hash of namespace bindings may be appended:
node.search('.//bike:tire', {'bike' => 'http://schwinn.com/'}) node.search('bike|tire', {'bike' => 'http://schwinn.com/'})
For XPath
queries, a hash of variable bindings may also be appended to the namespace bindings. For example:
node.search('.//address[@domestic=$value]', nil, {:value => 'Yes'})
💡 Custom XPath
functions and CSS
pseudo-selectors may also be defined. To define custom functions create a class and implement the function you want to define, which will be in the ‘nokogiri` namespace in XPath
queries.
The first argument to the method will be the current matching NodeSet
. Any other arguments are ones that you pass in. Note that this class may appear anywhere in the argument list. For example:
handler = Class.new { def regex node_set, regex node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ } end }.new node.search('.//title[nokogiri:regex(., "\w+")]', 'div.employee:regex("[0-9]+")', handler)
See Searchable#xpath
and Searchable#css
for further usage help.