require "atom/entry" require "atom/feed" require "uri" # Two big, interrelated problems: # # * I probably shouldn't be playing around in REXML's namespace # * REXML isn't a great parser, and other options would be nice # # This shouldn't be hard to do, it's just tedious and non-critical module REXML # :nodoc: all class Document def to_atom_entry base = "" self.root.to_atom_entry base end def to_atom_feed base = "" self.root.to_atom_feed base end end class Element def get_atom_element name XPath.first(self, "./atom:#{name}", { "atom" => Atom::NS }) end def each_atom_element name XPath.each(self, "./atom:#{name}", { "atom" => Atom::NS }) do |elem| yield elem end end def get_extensions # XXX also look for attributes children.find_all { |child| child.respond_to? :namespace and child.namespace != Atom::NS } end # get the text content of a descendant element in the Atom namespace def get_atom_text name elem = get_atom_element name if elem elem.text else nil end end # a workaround for the odd way in which REXML handles namespaces # returns the value of the attribute +name+ that's in the same namespace as this element def ns_attr name if not self.prefix.empty? attr = self.prefix + ":" + name else attr = name end self.attributes[attr] end def fill_text_construct(entry, name) text = get_atom_element(name) if text type = text.ns_attr("type") src = text.ns_attr("src") if src and name == :content # the only content is out of line entry.send( "#{name}=".to_sym, "") entry.send(name.to_sym)["src"] = src elsif type == "xhtml" div = XPath.first(text, "./xhtml:div", { "xhtml" => XHTML::NS }) unless div raise "Refusing to parse type='xhtml' with no
wrapper" end # content is the serialized content of the
wrapper entry.send( "#{name}=".to_sym, div ) else raw = text.text entry.send( "#{name}=", raw ) end if text.attributes["xml:base"] entry.send(name.to_sym).base = text.attributes["xml:base"] end if type and type != "text" entry.send(name.to_sym)["type"] = type end end end def fill_elem_element(top, kind) each_atom_element(kind) do |elem| person = top.send("#{kind}s".to_sym).new ["name", "uri", "email"].each do |name| person.send("#{name}=".to_sym, elem.get_atom_text(name)) end end end def fill_attr_element(top, array, kind) each_atom_element(kind) do |elem| thing = array.new thing.class.attrs.each do |name,req| value = elem.ns_attr name.to_s if value and name == :href thing[name.to_s] = (top.base.to_uri + value).to_s elsif value thing[name.to_s] = value end end end end # 'base' is the URI that you fetched this document from. def to_atom_entry base = "" unless self.name == "entry" and self.namespace == Atom::NS raise TypeError, "this isn't an atom:entry! (name: #{self.name}, ns: #{self.namespace})" end entry = Atom::Entry.new entry.base = if attributes["xml:base"] (URI.parse(base) + attributes["xml:base"]).to_s else # go with the URL we were passed in base end # Text constructs entry.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r| fill_text_construct(entry, n) end ["id", "published", "updated"].each do |name| entry.send("#{name}=".to_sym, get_atom_text(name)) end ["author", "contributor"].each do |type| fill_elem_element(entry, type) end {"link" => entry.links, "category" => entry.categories}.each do |k,v| fill_attr_element(entry, v, k) end # extension elements get_extensions.each do |elem| entry.extensions << elem.dup # otherwise they get removed from the doc end entry end # 'base' is the URI that you fetched this document from. def to_atom_feed base = "" unless self.name == "feed" and self.namespace == Atom::NS raise TypeError, "this isn't an atom:feed! (name: #{self.name}, ns: #{self.namespace})" end feed = Atom::Feed.new feed.base = if attributes["xml:base"] (URI.parse(base) + attributes["xml:base"]).to_s else # go with the URL we were passed in base end # Text constructs feed.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r| fill_text_construct(feed, n) end ["id", "updated", "generator", "icon", "logo"].each do |name| feed.send("#{name}=".to_sym, get_atom_text(name)) end ["author", "contributor"].each do |type| fill_elem_element(feed, type) end {"link" => feed.links, "category" => feed.categories}.each do |k,v| fill_attr_element(feed, v, k) end each_atom_element("entry") do |elem| feed << elem.to_atom_entry(feed.base) end get_extensions.each do |elem| # have to duplicate them, or they'll get removed from the doc feed.extensions << elem.dup end feed end end end