Class: Hpricot::Elements

Inherits:
Array
  • Object
show all
Defined in:
lib/hpricot/inspect.rb,
lib/hpricot/elements.rb

Overview

and Hpricot::Container::Trav.

Constant Summary collapse

ATTR_RE =

“ (for emacs)

%r!\[ *(?:(@)([\w\(\)-]+)|([\w\(\)-]+\(\))) *([~\!\|\*$\^=]*) *'?"?([^'"]*)'?"? *\]!i
BRACK_RE =
%r!(\[) *([^\]]*) *\]+!i
FUNC_RE =
%r!(:)?([a-zA-Z0-9\*_-]*)\( *[\"']?([^ \)]*?)['\"]? *\)!
CUST_RE =
%r!(:)([a-zA-Z0-9\*_-]*)()!
CATCH_RE =
%r!([:\.#]*)([a-zA-Z0-9\*_-]+)!

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.expand(ele1, ele2, excl = false) ⇒ Object

Given two elements, attempt to gather an Elements array of everything between (and including) those two elements.



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/hpricot/elements.rb', line 319

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

.filter(nodes, expr, truth = true) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/hpricot/elements.rb', line 274

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).join}"
        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
            args << -1
            nodes = Elements[*nodes.find_all do |x|
                                  args[-1] += 1
                                  x.send(meth, *args) ? truth : !truth
                              end]
        end
    end
    [nodes, expr]
end

Instance Method Details

#add_class(class_name) ⇒ Object

Adds the class to all matched elements.

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

Now all paragraphs will have class=“bacon”.



226
227
228
229
230
231
232
233
# File 'lib/hpricot/elements.rb', line 226

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

#after(str = nil, &blk) ⇒ Object

Just after each element in this list, add some HTML. Pass in an HTML str, which is turned into Hpricot elements.



154
155
156
# File 'lib/hpricot/elements.rb', line 154

def after(str = nil, &blk)
  each { |x| x.parent.insert_after x.make(str, &blk), x }
end

#append(str = nil, &blk) ⇒ Object

Add to the end of the contents inside each element in this list. Pass in an HTML str, which is turned into Hpricot elements.



136
137
138
# File 'lib/hpricot/elements.rb', line 136

def append(str = nil, &blk)
  each { |x| x.html(x.children + x.make(str, &blk)) }
end

#at(expr, &blk) ⇒ Object Also known as: %

Searches this list for the first element (or child of these elements) matching the CSS or XPath expression expr. Root is assumed to be the element scanned.

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



67
68
69
70
71
72
73
# File 'lib/hpricot/elements.rb', line 67

def at(expr, &blk)
  if expr.kind_of? Fixnum
    super
  else
    search(expr, &blk)[0]
  end
end

#attr(key, value = nil, &blk) ⇒ Object Also known as: set

Gets and sets attributes on all matched elements.

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

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

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

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

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

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

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

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

This example adds a #top anchor to each link.



205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/hpricot/elements.rb', line 205

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

#before(str = nil, &blk) ⇒ Object

Add some HTML just previous to each element in this list. Pass in an HTML str, which is turned into Hpricot elements.



148
149
150
# File 'lib/hpricot/elements.rb', line 148

def before(str = nil, &blk)
  each { |x| x.parent.insert_before x.make(str, &blk), x }
end

#emptyObject

Empty the elements in this list, by removing their insides.

doc = Hpricot("<p> We have <i>so much</i> to say.</p>")
doc.search("i").empty
doc.to_html
  => "<p> We have <i></i> to say.</p>"


130
131
132
# File 'lib/hpricot/elements.rb', line 130

def empty
  each { |x| x.inner_html = nil }
end

#filter(expr) ⇒ Object



351
352
353
354
# File 'lib/hpricot/elements.rb', line 351

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

#inner_html(*string) ⇒ Object Also known as: html, innerHTML

Returns an HTML fragment built of the contents of each element in this list.

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



86
87
88
89
90
91
92
# File 'lib/hpricot/elements.rb', line 86

def inner_html(*string)
  if string.empty?
    map { |x| x.inner_html }.join
  else
    x = self.inner_html = string.pop || x
  end
end

#inner_html=(string) ⇒ Object Also known as: html=, innerHTML=

Replaces the contents of each element in this list. Supply an HTML string, which is loaded into Hpricot objects and inserted into every element in this list.



99
100
101
# File 'lib/hpricot/elements.rb', line 99

def inner_html=(string)
  each { |x| x.inner_html = string }
end

#inner_textObject Also known as: text

Returns an string containing the text contents of each element in this list. All HTML tags are removed.



107
108
109
# File 'lib/hpricot/elements.rb', line 107

def inner_text
  map { |x| x.inner_text }.join
end

#not(expr) ⇒ Object



356
357
358
359
360
361
362
363
# File 'lib/hpricot/elements.rb', line 356

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

#prepend(str = nil, &blk) ⇒ Object

Add to the start of the contents inside each element in this list. Pass in an HTML str, which is turned into Hpricot elements.



142
143
144
# File 'lib/hpricot/elements.rb', line 142

def prepend(str = nil, &blk)
  each { |x| x.html(x.make(str, &blk) + x.children) }
end

#pretty_print(q) ⇒ Object



6
7
8
# File 'lib/hpricot/inspect.rb', line 6

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

#removeObject

Remove all elements in this list from the document which contains them.

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


119
120
121
# File 'lib/hpricot/elements.rb', line 119

def remove
  each { |x| x.parent.children.delete(x) }
end

#remove_attr(name) ⇒ Object

Remove an attribute from each of the matched elements.

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


239
240
241
242
243
244
245
# File 'lib/hpricot/elements.rb', line 239

def remove_attr name
  each do |el|
    next unless el.respond_to? :remove_attribute
    el.remove_attribute(name)
  end
  self
end

#remove_class(name = nil) ⇒ Object

Removes a class from all matched elements.

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

Or, to remove all classes:

(doc/"span").remove_class


255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/hpricot/elements.rb', line 255

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

#search(*expr, &blk) ⇒ Object Also known as: /

Searches this list for any elements (or children of these elements) matching the CSS or XPath expression expr. Root is assumed to be the element scanned.

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



58
59
60
# File 'lib/hpricot/elements.rb', line 58

def search(*expr,&blk)
  Elements[*map { |x| x.search(*expr,&blk) }.flatten.uniq]
end

#to_htmlObject Also known as: to_s

Convert this group of elements into a complete HTML fragment, returned as a string.



78
79
80
# File 'lib/hpricot/elements.rb', line 78

def to_html
  map { |x| x.output("") }.join
end

#wrap(str = nil, &blk) ⇒ Object

Wraps each element in the list inside the element created by HTML str. If more than one element is found in the string, Hpricot locates the deepest spot inside the first element.

doc.search("a[@href]").
    wrap(%{<div class="link"><div class="link_inner"></div></div>})

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



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/hpricot/elements.rb', line 166

def wrap(str = nil, &blk)
  each do |x|
    wrap = x.make(str, &blk)
    nest = wrap.detect { |w| w.respond_to? :children }
    unless nest
      raise "No wrapping element found."
    end
    x.parent.replace_child(x, wrap)
    nest = nest.children.first until nest.empty?
    nest.html([x])
  end
end