Class: KindDom::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/kind_dom/base.rb

Overview

KindDom provides graceful access to the the DOM of an XML document using three methods of kindness:

  • #collection_of to select a collection of nodes

  • #first_of to select one node

  • #content_for to get node content.

The original libxml behavior of the XML document is preserved through the #dom accessor.

As a contrived example, in the controller:

@results = KindDom::Base.new(xml_data)

In the view:

<% @results.first_of('//item') do |item| -%>
  <p>(This block is only executed if `item` is found.)</p>

  <% item.content_for('title', '(Untitled)') do |content| -%>
    <h2><%=h content %></h2>
    <p>(This header will show "(Untitled)" if `title` is blank or not found.)</p>
  <% end -%>

  <% item.content_for('description') do |content| -%>
    <p><%= item.content_for('@updated_at') {|date| "<em>#{date}</em> -- " } %>
      <%=h content %></p>
    <p>(This block is only executed if `description` has content.)</p>
  <% end -%>
<% end -%>

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(xml_in = nil, opts = {}) ⇒ Base

A new KindDom object may be created from raw XML [string] data, or an already instantiated KindDom::Base, XML::Node or XML::Document.

Caches intermediate found values, before yielding to the optional block. Disable the cache with opt ‘:find_cache => false` or set #find_cache to false

If you change the XML document through the #dom accessor, then you must disable or manually sweep the cache to avoid stale XPath results.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kind_dom/base.rb', line 47

def initialize(xml_in=nil, opts={})
  unless xml_in.nil?
    case 
    when xml_in.kind_of?(KindDom::Base)
      @dom = xml_in.dom
    when xml_in.kind_of?(XML::Document), xml_in.kind_of?(XML::Node)
      @dom = xml_in
    when xml_in.kind_of?(String)
      if XML::Parser.respond_to?(:string)
        parser = XML::Parser.string(xml_in)
      else  # for old libxml-ruby compatibility
        parser = XML::Parser.new
        parser.string = xml_in
      end
      @dom = parser.parse
    end
  end
  @find_cache = {} if opts[:find_cache].nil? ? true : opts[:find_cache]
rescue XML::Parser::ParseError
ensure
  return self
end

Instance Attribute Details

#domObject

Returns the value of attribute dom.



35
36
37
# File 'lib/kind_dom/base.rb', line 35

def dom
  @dom
end

#find_cacheObject

Returns the value of attribute find_cache.



36
37
38
# File 'lib/kind_dom/base.rb', line 36

def find_cache
  @find_cache
end

Instance Method Details

#collection_of(xpath, default = nil) ⇒ Object

Retrieve a collection (Array) of DOM nodes selected by the XPath.

Each node is returned as KindDom to support #content_for, #collection_of & #first_of.

When a block is provided, it will be called with the found collection (or default) before returning.



110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/kind_dom/base.rb', line 110

def collection_of(xpath, default=nil)      # :yields: found_collection
  c = cache "collection_of(#{xpath})" do
    @dom.find(xpath).collect {|n| self.class.new(n) }
  end
rescue NoMethodError
ensure
  c = c.blank?||c.size<1 ? default : c
  if block_given? and !c.nil?
    return yield(c)
  else
    return c
  end
end

#content_for(xpath = '.', default = nil) ⇒ Object

Retrieve the contents of the first node or attribute selected by the XPath; defaults to the current node, “.”

Optional second argument is the default value to return if the DOM find fails.

When a block is provided, it will be called with the found content (or default) before returning.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/kind_dom/base.rb', line 78

def content_for(xpath='.', default=nil)       # :yields: found_content
  content = cache "content_for(#{xpath})" do
    node = case @dom.class.to_s
    when 'XML::Document' then  # for libxml-ruby 0.5.x compatibility
      @dom.root.find_first(xpath)
    else # 'XML::Node'
      @dom.find_first(xpath)
    end
    case node.class.to_s
    when 'XML::Attr', 'LibXML::XML::Attr' then
      node.value
    else
      node.content
    end
  end
rescue NoMethodError
ensure
  content = content.blank? ? default : content
  if block_given? and !content.blank?
    return yield(content)
  else
    return content
  end
end

#first_of(xpath, default = nil) ⇒ Object

Retrieve the first DOM node selected by the XPath.

The node is returned as KindDom to support #content_for, #collection_of & #first_of.

When a block is provided, it will be called with the found node (or default) before returning.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/kind_dom/base.rb', line 131

def first_of(xpath, default=nil)      # :yields: found_node
  n = cache "first_of(#{xpath})" do
    case @dom.class.to_s
    when 'XML::Document' then  # for libxml-ruby 0.5.x compatibility
      @dom.root.find_first(xpath)
    else # 'XML::Node'
      @dom.find_first(xpath)
    end
  end
rescue NoMethodError
ensure
  n = n.blank? ? default : self.class.new(n)
  if block_given? and !n.blank?
    return yield(n)
  else
    return n
  end
end