class Nokogiri::XML::NodeSet - nokogiri-1.15.2 Documentation

# 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`

### Attributes

document[RW]

The `Document` this `NodeSet` is associated with

### Public Class Methods

new(document, list = []) { |self| ... } click to toggle source

Create a `NodeSet` with `document` defaulting to `list`

    # 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

### Public Instance Methods

search *paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]
Alias for: at
&(node_set) click to toggle source

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"));
    }

+(p1)
Alias for: |
-(node_set) click to toggle source

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"));
    }

<<(p1)
Alias for: push
==(other) click to toggle source

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 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

[index] → Node or nil click to toggle source
[start, length] → NodeSet or nil
[range] → NodeSet or nil

`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));
    }

Also aliased as: slice
add_class(name) click to toggle source

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 139
    def add_class(name)
      each do |el|
        el.add_class(name)
      end
      self
    end

after(datum) click to toggle source

Insert `datum` after the last `Node` in this `NodeSet`

    # File lib/nokogiri/xml/node_set.rb, line 69
    def after(datum)
      last.after(datum)
    end

append_class(name) click to toggle source

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 151
    def append_class(name)
      each do |el|
        el.append_class(name)
      end
      self
    end

search *paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class] click to toggle source

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]

Calls superclass method `Nokogiri::XML::Searchable#at`

    # 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

Also aliased as: %
attr(key, value = nil) { |node| ... } click to toggle source

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 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

Also aliased as: set, attribute
attribute(key, value = nil, &block)
Alias for: attr
before(datum) click to toggle source

Insert `datum` before the first `Node` in this `NodeSet`

    # File lib/nokogiri/xml/node_set.rb, line 63
    def before(datum)
      first.before(datum)
    end

children() click to toggle source

Returns a new `NodeSet` containing all the children of all the nodes in the `NodeSet`

    # File lib/nokogiri/xml/node_set.rb, line 406
    def children
      node_set = NodeSet.new(document)
      each do |node|
        node.children.each { |n| node_set.push(n) }
      end
      node_set
    end

dup
Alias for: dup
css *rules, [namespace-bindings, custom-pseudo-class] click to toggle source

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 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

deconstruct() → Array click to toggle source

Returns the members of this `NodeSet` as an array, to use in pattern matching.

⚡ This is an experimental feature, available since v1.14.0

    # File lib/nokogiri/xml/node_set.rb, line 440
    def deconstruct
      to_a
    end

delete(node) click to toggle source

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 ;
    }

dup click to toggle source

Duplicate this `NodeSet`. Note that the Nodes contained in the `NodeSet` are not duplicated (similar to how Array and other Enumerable classes work).

    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"));
    }

Also aliased as: clone
each() { |self| ... } click to toggle source

Iterate over each node, yielding to `block`

    # 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

empty?() click to toggle source

Is this `NodeSet` empty?

    # File lib/nokogiri/xml/node_set.rb, line 45
    def empty?
      length == 0
    end

filter(expr) click to toggle source

Filter this list for nodes that match `expr`

    # File lib/nokogiri/xml/node_set.rb, line 130
    def filter(expr)
      find_all { |node| node.matches?(expr) }
    end

first(n = nil) click to toggle source

Get the first element of the `NodeSet`.

    # 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

include?(node) click to toggle source

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);
    }

index(node = nil) { |member| ... } click to toggle source

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 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

inner_html(*args) click to toggle source

Get the inner html of all contained `Node` objects

    # File lib/nokogiri/xml/node_set.rb, line 260
    def inner_html(*args)
      collect { |j| j.inner_html(*args) }.join("")
    end

inner_text() click to toggle source

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 253
    def inner_text
      collect(&:inner_text).join("")
    end

Also aliased as: text
inspect() click to toggle source

Return a nicely formated string representation

    # File lib/nokogiri/xml/node_set.rb, line 427
    def inspect
      "[#{map(&:inspect).join(", ")}]"
    end

last() click to toggle source

Get the last element of the `NodeSet`.

    # File lib/nokogiri/xml/node_set.rb, line 39
    def last
      self[-1]
    end

length click to toggle source

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);
    }

Also aliased as: size
pop() click to toggle source

Removes the last element from set and returns it, or `nil` if the set is empty

    # File lib/nokogiri/xml/node_set.rb, line 374
    def pop
      return nil if length == 0

      delete(last)
    end

push(node) click to toggle source

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;
    }

Also aliased as: <<
unlink
Alias for: unlink
remove_attr(name) click to toggle source

Remove the attributed named `name` from all `Node` objects in the `NodeSet`

    # File lib/nokogiri/xml/node_set.rb, line 223
    def remove_attr(name)
      each { |el| el.delete(name) }
      self
    end

Also aliased as: remove_attribute
remove_attribute(name)
Alias for: remove_attr
remove_class(name = nil) click to toggle source

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 163
    def remove_class(name = nil)
      each do |el|
        el.remove_class(name)
      end
      self
    end

reverse() click to toggle source

Returns a new `NodeSet` containing all the nodes in the `NodeSet` in reverse order

    # File lib/nokogiri/xml/node_set.rb, line 417
    def reverse
      node_set = NodeSet.new(document)
      (length - 1).downto(0) do |x|
        node_set.push(self[x])
      end
      node_set
    end

set(key, value = nil, &block)
Alias for: attr
shift() click to toggle source

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 383
    def shift
      return nil if length == 0

      delete(first)
    end

length
Alias for: length
slice(index) → Node or nil
slice(start, length) → NodeSet or nil
slice(range) → NodeSet or nil

`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.

Alias for: []
text()
Alias for: inner_text
to_a click to toggle source

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;
    }

Also aliased as: to_ary
to_a
Alias for: to_a
to_html(*args) click to toggle source

Convert this `NodeSet` to `HTML`

    # 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

to_s() click to toggle source

Convert this `NodeSet` to a string.

    # File lib/nokogiri/xml/node_set.rb, line 335
    def to_s
      map(&:to_s).join
    end

to_xhtml(*args) click to toggle source

Convert this `NodeSet` to XHTML

    # File lib/nokogiri/xml/node_set.rb, line 358
    def to_xhtml(*args)
      map { |x| x.to_xhtml(*args) }.join
    end

to_xml(*args) click to toggle source

Convert this `NodeSet` to `XML`

    # File lib/nokogiri/xml/node_set.rb, line 364
    def to_xml(*args)
      map { |x| x.to_xml(*args) }.join
    end

unlink click to toggle source

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 ;
    }

Also aliased as: remove
wrap(markup) → self click to toggle source
wrap(node) → 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 328
    def wrap(node_or_tags)
      map { |node| node.wrap(node_or_tags) }
      self
    end

xpath *paths, [namespace-bindings, variable-bindings, custom-handler-class] click to toggle source

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 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

|(node_set) click to toggle source

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"));
    }

Also aliased as: +