module Hpricot::Traverse
def self.filter(tok, &blk)
def self.filter(tok, &blk) define_method("filter[#{tok.is_a?(String) ? tok : tok.inspect}]", &blk) end
def after(html = nil, &blk)
def after(html = nil, &blk) parent.insert_after(make(html, &blk), self) end
def at(expr)
Find the first matching node for the CSS or XPath
def at(expr) search(expr).first end
def before(html = nil, &blk)
def before(html = nil, &blk) parent.insert_before(make(html, &blk), self) end
def bogusetag?() BogusETag::Trav === self end
def bogusetag?() BogusETag::Trav === self end
def children_of_type(tag_name)
#=> [...array of paragraphs...]
ele.children_of_type('p')
Find children of a given +tag_name+.
def children_of_type(tag_name) if respond_to? :children children.find_all do |x| x.respond_to?(:pathname) && x.pathname == tag_name end end end
def clean_path(path)
def clean_path(path) path.gsub(/^\s+|\s+$/, '') end
def comment?() Comment::Trav === self end
def comment?() Comment::Trav === self end
def css_path
Builds a unique CSS string for this node, from the
def css_path if elem? and has_attribute? 'id' "##{get_attribute('id')}" else sim, i, id = 0, 0, 0 parent.children.each do |e| id = sim if e == self sim += 1 if e.pathname == self.pathname end if parent.children p = parent.css_path p = p ? "#{p} > #{self.pathname}" : self.pathname p += ":nth(#{id})" if sim >= 2 p end end
def doc?() Doc::Trav === self end
def doc?() Doc::Trav === self end
def doctype?() DocType::Trav === self end
def doctype?() DocType::Trav === self end
def elem?() Elem::Trav === self end
def elem?() Elem::Trav === self end
def following
def following sibs = parent.children si = sibs.index(self) + 1 return Elements[*sibs[si...sibs.length]] end
def get_subnode(*indexes)
def get_subnode(*indexes) n = self indexes.each {|index| n = n.get_subnode_internal(index) } n end
def html(inner = nil, &blk)
def html(inner = nil, &blk) if inner or blk altered! case inner when Array self.children = inner else self.children = make(inner, &blk) end reparent self.children else if respond_to?(:children) and children children.map { |x| x.output("") }.join else "" end end end
def index(name)
def index(name) i = 0 return i if name == "*" children.each do |x| return i if (x.respond_to?(:name) and name == x.name) or (x.text? and name == "text()") i += 1 end if children -1 end
def inner_html=(inner)
Inserts new contents into the current node, based on
def inner_html=(inner) html(inner || []) end
def inner_text
Builds a string from the text contained in this node. All
def inner_text if respond_to?(:children) and children children.map { |x| x.inner_text }.join else "" end end
def make(input = nil, &blk)
Parses an HTML string, making an HTML fragment based on
def make(input = nil, &blk) if parent and parent.respond_to? :make parent.make(input, &blk) else Hpricot.make(input, &blk).children end end
def next
Returns the node neighboring this node to the south: just below it.
def next sib = parent.children sib[sib.index(self) + 1] if parent end
def node_position
def node_position parent.children.index(self) end
def nodes_at(*pos)
ele.nodes_at(1, 5, 7) # gets three nodes at offsets below the current node
ele.nodes_at(-3..-1, 1..3) # gets three nodes before and three after
This method also accepts ranges and sets of numbers.
nodes_at(1). Or, to get the previous node, use nodes_at(1).
to this node. So, for example, to get the next node, you could use
Puts together an array of neighboring nodes based on their proximity
def nodes_at(*pos) sib = parent.children i, si = 0, sib.index(self) pos.map! do |r| if r.is_a?(Range) and r.begin.is_a?(String) r = Range.new(parent.index(r.begin)-si, parent.index(r.end)-si, r.exclude_end?) end r end p pos Elements[* sib.select do |x| sel = case i - si when *pos true end i += 1 sel end ] end
def position
def position parent.children_of_type(self.pathname).index(self) end
def preceding
def preceding sibs = parent.children si = sibs.index(self) return Elements[*sibs[0...si]] end
def previous
Returns to node neighboring this node to the north: just above it.
def previous sib = parent.children x = sib.index(self) - 1 sib[x] if sib and x >= 0 end
def procins?() ProcIns::Trav === self end
def procins?() ProcIns::Trav === self end
def reparent(nodes)
def reparent(nodes) return unless nodes altered! [*nodes].each { |e| e.parent = self } end
def search(expr, &blk)
containing the matching nodes. If +blk+ is given, it
the CSS or XPath +expr+. Returns an Elements array
Searches this node for all elements matching
def search(expr, &blk) if Range === expr return Elements.expand(at(expr.begin), at(expr.end), expr.exclude_end?) end last = nil nodes = [self] done = [] expr = expr.to_s hist = [] until expr.empty? expr = clean_path(expr) expr.gsub!(%r!^//!, '') case expr when %r!^/?\.\.! last = expr = $' nodes.map! { |node| node.parent } when %r!^[>/]\s*! last = expr = $' nodes = Elements[*nodes.map { |node| node.children if node.respond_to? :children }.flatten.compact] when %r!^\+! last = expr = $' nodes.map! do |node| siblings = node.parent.children siblings[siblings.index(node)+1] end nodes.compact! when %r!^~! last = expr = $' nodes.map! do |node| siblings = node.parent.children siblings[(siblings.index(node)+1)..-1] end nodes.flatten! when %r!^[|,]! last = expr = " #$'" nodes.shift if nodes.first == self done += nodes nodes = [self] else m = expr.match(%r!^([#.]?)([a-z0-9\\*_-]*)!i).to_a after = $' mt = after[%r!:[a-z0-9\\*_-]+!i, 0] oop = false if mt and not (mt == ":not" or Traverse.method_defined? "filter[#{mt}]") after = $' m[2] += mt expr = after end if m[1] == '#' oid = get_element_by_id(m[2]) nodes = oid ? [oid] : [] expr = after else m[2] = "*" if after =~ /^\(\)/ || m[2] == "" || m[1] == "." ret = [] nodes.each do |node| case m[2] when '*' node.traverse_element { |n| ret << n } else if node.respond_to? :get_elements_by_tag_name ret += [*node.get_elements_by_tag_name(m[2])] - [*(node unless last)] end end end nodes = ret end last = nil end hist << expr break if hist[-1] == hist[-2] nodes, expr = Elements.filter(nodes, expr) end nodes = done + nodes.flatten.uniq if blk nodes.each(&blk) self else Elements[*nodes] end end
def swap(html = nil, &blk)
Replace this element and its contents with the nodes contained
def swap(html = nil, &blk) parent.altered! parent.replace_child(self, make(html, &blk)) end
def text?() Text::Trav === self end
def text?() Text::Trav === self end
def to_html
If you need to write to a stream, try calling output(io)
Builds an HTML string from this node and its contents.
def to_html output("") end
def to_original_html
Attempts to preserve the original HTML of the document, only
def to_original_html output("", :preserve => true) end
def to_plain_text
Builds a string from the text contained in this node. All
def to_plain_text if respond_to?(:children) and children children.map { |x| x.to_plain_text }.join.strip.gsub(/\n{2,}/, "\n\n") else "" end end
def traverse_element(*names, &block) # :yields: element
{emptyelem <{http://www.w3.org/1999/xhtml}meta name="author" content="Who am I?">}
{emptyelem <{http://www.w3.org/1999/xhtml}meta name="robots" content="index,nofollow">}
# =>
t.traverse_element("{http://www.w3.org/1999/xhtml}meta") {|e| p e}
End