class Hpricot::Elements

and Hpricot::Container::Trav.
Most of the useful element methods are in the mixins Hpricot::Traverse
end
end
ary << ele # stuff away all the elements under the h3
while ele = h3.next_sibling
doc.search(“h3”).each do |h3|
A good method for this is next_sibling:
and grab all the tags underneath the header, but not inside the header.
For example, you may want to search for all the H3 header tags in a document
which can do what you need.
loop through the elements and find a method in Hpricot::Container::Trav
If you can’t find a method here that does what you need, you may need to
== Getting More Detailed
#=> “That’s my fork, Tyler.”
doc.to_html
doc.at(“b”).swap(“fork”)
doc = Hpricot(“That’s my spoon, Tyler.”)
the document you started searching from.
When you’re altering elements in the list, your changes will be reflected in
== Altering Elements
elements = elements.at(“img”)
elements = elements.search(“/a”)
elements = doc.search(“/div/p”)
and search methods you can use on plain elements.
done. Well, you can continue searching the list by using the same at
Usually the Hpricot::Elements you’re working on comes from a search you’ve
== Continuing Searches
Hpricot::Doc, etc.)
Assuming that ele1, ele2 and ele3 contain element objects (Hpricot::Elem,
Hpricot::Elements[ele1, ele2, ele3]
If you need to create an element array from regular elements:
added for altering elements contained in the array.
Hpricot::Elements is an extension of Ruby’s array class, with some methods
a group. Or you may want to perform the same action on each of them.
Once you’ve matched a list of elements, you will often need to handle them as

def self.expand(ele1, ele2, excl=false)

(and including) those two elements.
Given two elements, attempt to gather an Elements array of everything between
def self.expand(ele1, ele2, excl=false)
  ary = []
  offset = excl ? -1 : 0
  if ele1 and ele2
    # let's quickly take care of siblings
    if ele1.parent == ele2.parent
      ary = ele1.parent.children[ele1.node_position..(ele2.node_position+offset)]
    else
      # find common parent
      p, ele1_p = ele1, [ele1]
      ele1_p.unshift p while p.respond_to?(:parent) and p = p.parent
      p, ele2_p = ele2, [ele2]
      ele2_p.unshift p while p.respond_to?(:parent) and p = p.parent
      common_parent = ele1_p.zip(ele2_p).select { |p1, p2| p1 == p2 }.flatten.last
      child = nil
      if ele1 == common_parent
        child = ele2
      elsif ele2 == common_parent
        child = ele1
      end
      if child
        ary = common_parent.children[0..(child.node_position+offset)]
      end
    end
  end
  return Elements[*ary]
end

def self.filter(nodes, expr, truth = true)

def self.filter(nodes, expr, truth = true)
    until expr.empty?
        _, *m = *expr.match(/^(?:#{ATTR_RE}|#{BRACK_RE}|#{FUNC_RE}|#{CUST_RE}|#{CATCH_RE})/)
        break unless _
        expr = $'
        m.compact!
        if m[0] == '@'
            m[0] = "@#{m.slice!(2,1)}"
        end
        if m[0] == '[' && m[1] =~ /^\d+$/
            m = [":", "nth", m[1].to_i-1]
        end
        if m[0] == ":" && m[1] == "not"
            nodes, = Elements.filter(nodes, m[2], false)
        elsif "#{m[0]}#{m[1]}" =~ /^(:even|:odd)$/
            new_nodes = []
            nodes.each_with_index {|n,i| new_nodes.push(n) if (i % 2 == (m[1] == "even" ? 0 : 1)) }
            nodes = new_nodes
        elsif "#{m[0]}#{m[1]}" =~ /^(:first|:last)$/
            nodes = [nodes.send(m[1])]
        else
            meth = "filter[#{m[0]}#{m[1]}]" unless m[0].empty?
            if meth and Traverse.method_defined? meth
                args = m[2..-1]
            else
                meth = "filter[#{m[0]}]"
                if Traverse.method_defined? meth
                    args = m[1..-1]
                end
            end
            i = -1
            nodes = Elements[*nodes.find_all do |x| 
                                  i += 1
                                  x.send(meth, *([*args] + [i])) ? truth : !truth
                              end]
        end
    end
    [nodes, expr]
end

def add_class class_name

Now all paragraphs will have class="bacon".

(doc/"p").add_class("bacon")

Adds the class to all matched elements.
def add_class class_name
  each do |el|
    next unless el.respond_to? :get_attribute
    classes = el.get_attribute('class').to_s.split(" ")
    el.set_attribute('class', classes.push(class_name).uniq.join(" "))
  end
  self
end

def after(str = nil, &blk)

Pass in an HTML +str+, which is turned into Hpricot elements.
Just after each element in this list, add some HTML.
def after(str = nil, &blk)
  each { |x| x.parent.insert_after x.make(str, &blk), x }
end

def append(str = nil, &blk)

Pass in an HTML +str+, which is turned into Hpricot elements.
Add to the end of the contents inside each element in this list.
def append(str = nil, &blk)
  each { |x| x.html(x.children + x.make(str, &blk)) }
end

def at(expr, &blk)

See Hpricot::Container::Trav.at for more.

the CSS or XPath expression +expr+. Root is assumed to be the element scanned.
Searches this list for the first element (or child of these elements) matching
def at(expr, &blk)
  search(expr, &blk).first
end

def attr key, value = nil, &blk


This example adds a #top anchor to each link.

records.attr("href") { |e| e['href'] + "#top" }

the new value of the attribute.
it belongs to. The block will pass in an element. Return from the block
Lastly, a block can be used to rewrite an attribute based on the element

(doc/"a").attr(:class => "basic", :href => "http://hackety.org/")

You may also use a Hash to set a series of attributes:

doc.search("p").attr("class", "basic")

matched elements.
Or, pass in a +key+ and +value+. This will set an attribute for all

#=> "http://hacketyhack.net/"
doc.search("a").attr("href")

attribute isn't found.
assigned to that attribute for the first elements. Or +nil+ if the
Pass in a +key+ on its own and this method will return the string value

Gets and sets attributes on all matched elements.
def attr key, value = nil, &blk
  if value or blk
    each do |el|
      el.set_attribute(key, value || blk[el])
    end
    return self      
  end    
  if key.is_a? Hash
    key.each { |k,v| self.attr(k,v) }
    return self
  else
    return self[0].get_attribute(key)
  end
end

def before(str = nil, &blk)

Pass in an HTML +str+, which is turned into Hpricot elements.
Add some HTML just previous to each element in this list.
def before(str = nil, &blk)
  each { |x| x.parent.insert_before x.make(str, &blk), x }
end

def copy_node(node, l)

def copy_node(node, l)
    l.instance_variables.each do |iv|
        node.instance_variable_set(iv, l.instance_variable_get(iv))
    end
end

def empty


=> "

We have to say.

"
doc.to_html
doc.search("i").empty
doc = Hpricot("

We have so much to say.

")

Empty the elements in this list, by removing their insides.
def empty
  each { |x| x.inner_html = nil }
end

def filter(expr)

def filter(expr)
    nodes, = Elements.filter(self, expr)
    nodes
end

def inner_html(*string)

If a HTML +string+ is supplied, this method acts like inner_html=.

Returns an HTML fragment built of the contents of each element in this list.
def inner_html(*string)
  if string.empty?
    map { |x| x.inner_html }.join
  else
    x = self.inner_html = string.pop || x
  end
end

def inner_html=(string)

list.
which is loaded into Hpricot objects and inserted into every element in this
Replaces the contents of each element in this list. Supply an HTML +string+,
def inner_html=(string)
  each { |x| x.inner_html = string }
end

def inner_text

All HTML tags are removed.
Returns an string containing the text contents of each element in this list.
def inner_text
  map { |x| x.inner_text }.join
end

def not(expr)

def not(expr)
    if expr.is_a? Traverse
        nodes = self - [expr]
    else
        nodes, = Elements.filter(self, expr, false)
    end
    nodes
end

def prepend(str = nil, &blk)

Pass in an HTML +str+, which is turned into Hpricot elements.
Add to the start of the contents inside each element in this list.
def prepend(str = nil, &blk)
  each { |x| x.html(x.make(str, &blk) + x.children) }
end

def pretty_print(q)

def pretty_print(q)
  q.object_group(self) { super }
end

def remove


=> "Remove this: "
doc.to_html
doc.search("b").remove
doc = Hpricot("Remove this: here")

Remove all elements in this list from the document which contains them.
def remove
  each { |x| x.parent.children.delete(x) }
end

def remove_attr name


(doc/"input").remove_attr("disabled")

Remove an attribute from each of the matched elements.
def remove_attr name
  each do |el|
    next unless el.respond_to? :remove_attribute
    el.remove_attribute(name)
  end
  self      
end

def remove_class name = nil


(doc/"span").remove_class

Or, to remove all classes:

(doc/"span").remove_class("lightgrey")

Removes a class from all matched elements.
def remove_class name = nil
  each do |el|
    next unless el.respond_to? :get_attribute
    if name
      classes = el.get_attribute('class').to_s.split(" ")
      el.set_attribute('class', (classes - [name]).uniq.join(" "))
    else
      el.remove_attribute("class")
    end
  end
  self      
end

def search(*expr,&blk)

See Hpricot::Container::Trav.search for more.

the CSS or XPath expression +expr+. Root is assumed to be the element scanned.
Searches this list for any elements (or children of these elements) matching
def search(*expr,&blk)
  Elements[*map { |x| x.search(*expr,&blk) }.flatten.uniq]
end

def to_html

string.
Convert this group of elements into a complete HTML fragment, returned as a
def to_html
  map { |x| x.output("") }.join
end

def wrap(str = nil, &blk)

This code wraps every link on the page inside a +div.link+ and a +div.link_inner+ nest.

wrap(%{})
doc.search("a[@href]").

deepest spot inside the first element.
If more than one element is found in the string, Hpricot locates the
Wraps each element in the list inside the element created by HTML +str+.
def wrap(str = nil, &blk)
  each do |x|
    wrap = x.make(str, &blk)
    nest = wrap.detect { |w| w.respond_to? :children }
    unless nest
      raise Exception, "No wrapping element found."
    end
    x.parent.replace_child(x, wrap)
    nest = nest.children.first until nest.empty?
    nest.html(nest.children + [x])
  end
end