class Atom::Element
Atom::Element
¶ ↑
Base Element
Object Class
You don't use this class directly. This is a base class of each element classes used in Atom
Syndication Format.
Attributes
accessor for xml-element(REXML::Element) object.
Public Class Methods
Attribute accessor generator
# File lib/atomutil.rb, line 423 def self.element_attr_accessor(name) name = name.to_s name.tr!('-', '_') class_eval(<<-EOS, __FILE__, __LINE__) def #{name} get_attr('#{name}') end def #{name}=(value) set_attr('#{name}', value) end EOS end
You can generate attribute accessor at once.
# File lib/atomutil.rb, line 436 def self.element_attr_accessors(*names) names.each{ |n| element_attr_accessor(n) } end
Generate datetime element accessor for indicated name.
Example:
class Entry < BaseEntry element_datetime_accessor :updated element_datetime_accessor :published end entry = Entry.new entry.updated = Time.now puts entry.updated.year puts entry.updated.month
# File lib/atomutil.rb, line 321 def self.element_datetime_accessor(name) name = name.to_s name.tr!('-', '_') class_eval(<<-EOS, __FILE__, __LINE__) def #{name} dt = get(@ns, '#{name}') dt.nil? ? nil : Time.iso8601(dt.text) end def #{name}=(value, attributes=nil) case value when Time date = value.iso8601 else date = value end set(@ns, '#{name}', date, attributes) end EOS end
You can set datetime accessor at once with this method
Example:
class Entry < BaseEntry element_datetime_accessor :updated, :published end entry = Entry.new entry.updated = Time.now puts entry.updated.year puts entry.updated.month
# File lib/atomutil.rb, line 351 def self.element_datetime_accessors(*names) names.each{ |n| element_datetime_accessor(n) } end
# File lib/atomutil.rb, line 248 def self.element_name(name=nil) unless name.nil? @element_name = name.to_s end @element_name end
# File lib/atomutil.rb, line 255 def self.element_ns(ns=nil) unless ns.nil? @element_ns = ns.is_a?(Namespace) ? ns : Namespace.new(:uri => ns) end @element_ns end
Generate useful accessor for the multiple element
Example:
class Entry < Element element_object_list_accessors :author, Author, :authors element_object_list_accessors :contributor, Contributor, :contributors end
# File lib/atomutil.rb, line 394 def self.element_object_list_accessor(name, ext_class, moniker=nil) name = name.to_s name.tr!('-', '_') unless moniker.nil? moniker = moniker.to_s moniker.tr!('-', '_') end elem_ns = ext_class.element_ns || ns class_eval(<<-EOS, __FILE__, __LINE__) def #{name} get_object('#{elem_ns}', '#{name}', #{ext_class}) end def #{name}=(stuff) set('#{elem_ns}', '#{name}', stuff) end def add_#{name}(stuff) add('#{elem_ns}', '#{name}', stuff) end EOS class_eval(<<-EOS, __FILE__, __LINE__) unless moniker.nil? def #{moniker} get_objects('#{elem_ns}', '#{name}', #{ext_class}) end def #{moniker}=(stuff) #{name} = stuff end EOS end
Generate element accessor for indicated name The generated accessors can deal with elements which has only simple text-node, such as title, summary, rights, and etc. Of course, these elements should handle more complex data. In such a case, you can control them directly with 'set' and 'get' method.
Example:
class Entry < Element element_text_accessor 'title' element_text_accessor 'summary' end elem = MyElement.new elem.title = "foo" elem.summary = "bar" puts elem.title #foo puts elem.summary #bar div = REXML::Element.new("<div><p>hoge</p></div>") elem.set('http://www.w3.org/2005/Atom', 'title', div, { :type => 'xhtml' })
# File lib/atomutil.rb, line 283 def self.element_text_accessor(name) name = name.to_s name.tr!('-', '_') class_eval(<<-EOS, __FILE__, __LINE__) def #{name} value = get(@ns, '#{name}') value.nil? ? nil : value.text end def #{name}=(value, attributes=nil) set(@ns, '#{name}', value, attributes) end EOS end
You can set text_accessor at once with this method
Example:
class Entry < BaseEntry element_text_accessors :title, :summary end entry = Entry.new entry.title = "hoge" puts entry.title #hoge
# File lib/atomutil.rb, line 306 def self.element_text_accessors(*names) names.each{ |n| element_text_accessor(n) } end
Generates text accessor for multiple value.
Example:
# File lib/atomutil.rb, line 357 def self.element_text_list_accessor(name, moniker=nil) name = name.to_s name.tr!('-', '_') unless moniker.nil? moniker = moniker.to_s moniker.tr!('-', '_') end elem_ns = element_ns || ns class_eval(<<-EOS, __FILE__, __LINE__) def #{name} value = getlist('#{elem_ns}', '#{name}') value.empty?? nil : value.first end def #{name}=(stuff) set('#{elem_ns}', '#{name}', stuff) end def add_#{name}(stuff) add('#{elem_ns}', '#{name}', stuff) end EOS class_eval(<<-EOS, __FILE__, __LINE__) unless moniker.nil? def #{moniker} getlist('#{elem_ns}', '#{name}') end def #{moniker}=(stuff) #{name} = stuff end EOS end
# File lib/atomutil.rb, line 235 def self.new(params={}) obj = super(params) yield(obj) if block_given? obj end
Setup element.
# File lib/atomutil.rb, line 441 def initialize(params={}) @ns = params.has_key?(:namespace) ? params[:namespace] \ : self.class.element_ns ? self.class.element_ns \ : self.class.ns @elem = params.has_key?(:elem) ? params[:elem] : REXML::Element.new(self.class.element_name) if @ns.is_a?(Namespace) unless @ns.prefix.nil? @elem.add_namespace @ns.prefix, @ns.uri else @elem.add_namespace @ns.uri end else @elem.add_namespace @ns end params.keys.each do |key| setter = "#{key}="; send(setter.to_sym, params[key]) if respond_to?(setter.to_sym) end end
# File lib/atomutil.rb, line 241 def self.ns(ns=nil) unless ns.nil? @@ns = ns.is_a?(Namespace) ? ns : Namespace.new(:uri => ns) end @@ns end
Public Instance Methods
Same as 'set', but when a element-name confliction occurs, append new element without overriding.
# File lib/atomutil.rb, line 505 def add(ns, element_name, value, attributes={}) element = REXML::Element.new(element_name) if ns.is_a?(Namespace) unless ns.prefix.nil? || ns.prefix.empty? element.name = "#{ns.prefix}:#{element_name}" element.add_namespace ns.prefix, ns.uri unless @ns == ns || @ns == ns.uri else element.add_namespace ns.uri unless @ns == ns || @ns == ns.uri end else element.add_namespace ns unless @ns == ns || @ns.to_s == ns end if value.is_a?(Element) value.elem.each_element do |e| element.add e.deep_clone end value.elem.attributes.each_attribute do |a| unless a.name =~ /^xmlns(?:\:)?/ element.add_attribute a end end #element.text = value.elem.text unless value.elem.text.nil? text = value.elem.get_text unless text.nil? element.text = REXML::Text.new(text.to_s, true, nil, true) end else if value.is_a?(REXML::Element) element.add_element value.deep_clone else element.add_text value.to_s end end element.add_attributes attributes unless attributes.nil? @elem.add_element element end
Get indicated element. If it matches multiple, returns first one.
elem = entry.get('http://example/2007/mynamespace', 'foo') ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/') elem = entry.get(ns, 'subject')
# File lib/atomutil.rb, line 549 def get(ns, element_name) getlist(ns, element_name).first end
Get attribute value for indicated key
# File lib/atomutil.rb, line 587 def get_attr(name) @elem.attributes[name.to_s] end
Get indicated elements as an object of the class you passed as thrid argument.
ns = Atom::Namespace.new(:uri => 'http://example.com/ns#') obj = entry.get_object(ns, 'mytag', MyClass) puts obj.class #MyClass
MyClass should inherit Atom::Element
# File lib/atomutil.rb, line 568 def get_object(ns, element_name, ext_class) elements = getlist(ns, element_name) return nil if elements.empty? ext_class.new(:namespace => ns, :elem => elements.first) end
Get all indicated elements as an object of the class you passed as thrid argument.
entry.get_objects(ns, 'mytag', MyClass).each{ |obj| p obj.class #MyClass }
# File lib/atomutil.rb, line 579 def get_objects(ns, element_name, ext_class) elements = getlist(ns, element_name) return [] if elements.empty? elements.collect do |e| ext_class.new(:namespace => ns, :elem => e) end end
Get indicated elements as array
ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/') elems = entry.getlist(ns, 'subject')
# File lib/atomutil.rb, line 557 def getlist(ns, element_name) @elem.get_elements(child_xpath(ns, element_name)) end
This method allows you to handle extra-element such as you can't represent with elements defined in Atom
namespace.
entry = Atom::Entry.new entry.set('http://example/2007/mynamespace', 'foo', 'bar')
Now your entry includes new element. <foo xmlns=“barexample/2007/mynamespace”>bar>
You also can add attributes
entry.set('http://example/2007/mynamespace', 'foo', 'bar', { :myattr => 'attr1', :myattr2 => 'attr2' })
And you can get following element from entry
<foo xmlns="http://example/2007/mynamespace" myattr="attr1" myattr2="attr2">bar</foo>
Or using prefix,
entry = Atom::Entry.new ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/') entry.set(ns, 'subject', 'buz')
Then your element contains
<dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">buz</dc:subject>
And in case you need to handle more complex element, pass the REXML::Element object which you customized as third argument instead of text-value.
custom_element = REXML::Element.new custom_child = REXML::Element.new('mychild') custom_child.add_text = 'child!' custom_element.add_element custom_child entry.set(ns, 'mynamespace', costom_element)
# File lib/atomutil.rb, line 498 def set(ns, element_name, value="", attributes=nil) xpath = child_xpath(ns, element_name) @elem.elements.delete_all(xpath) add(ns, element_name, value, attributes) end
Set attribute value for indicated key
# File lib/atomutil.rb, line 591 def set_attr(name, value) @elem.attributes[name.to_s] = value end
Convert to XML-Document and return it as string
# File lib/atomutil.rb, line 595 def to_s(*) doc = REXML::Document.new decl = REXML::XMLDecl.new("1.0", "utf-8") doc.add decl doc.add_element @elem doc.to_s end
Private Instance Methods
Get a xpath string to traverse child elements with namespace and name.
# File lib/atomutil.rb, line 604 def child_xpath(ns, element_name, attributes=nil) ns_uri = ns.is_a?(Namespace) ? ns.uri : ns unless !attributes.nil? && attributes.is_a?(Hash) "child::*[local-name()='#{element_name}' and namespace-uri()='#{ns_uri}']" else attr_str = attributes.collect{|key, val| "@#{key.to_s}='#{val}'"}.join(' and ') "child::*[local-name()='#{element_name}' and namespace-uri()='#{ns_uri}' and #{attr_str}]" end end