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).
Constants
- LOOKS_LIKE_XPATH
-
Included from Nokogiri::XML::Searchable
Regular expression used by
Searchable#searchto determine if a query string isCSSorXPath
Attributes
Public Class Methods
Source
# 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
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 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
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
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.
Source
# File lib/nokogiri/xml/node_set.rb, line 141 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 153 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 121 def at(*args) if args.length == 1 && args.first.is_a?(Numeric) return self[args.first] end super 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 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
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 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
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 442 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
# 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
Iterate over each node, yielding to block
Source
# File lib/nokogiri/xml/node_set.rb, line 47 def empty? length == 0 end
Is this NodeSet empty?
Source
# File lib/nokogiri/xml/node_set.rb, line 132 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 31 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 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
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 262 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 255 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 429 def inspect "[#{map(&:inspect).join(", ")}]" end
Return a nicely formatted string representation
Source
# File lib/nokogiri/xml/node_set.rb, line 41 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 376 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 225 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 165 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 385 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 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
Source
# File lib/nokogiri/xml/node_set.rb, line 337 def to_s map(&:to_s).join end
Convert this NodeSet to a string.
Source
# File lib/nokogiri/xml/node_set.rb, line 360 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 330 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 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
Search this node set for XPath paths. paths must be one or more XPath queries.
For more information see Nokogiri::XML::Searchable#xpath
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.