2009/05/19

BloggerAPI POST XML


# coding: utf-8
=begin
# post_xml.rb
# 2009-05-18.

# BloggerAPI POST Request で必要な XML の生成
<entry xmlns='http://www.w3.org/2005/Atom'>
<published>2009-06-01T00:00:00+09:00</published>
<app:control xmlns:app='http://www.w3.org/2007/app'>
<app:draft>yes</app:draft></app:control>
<title type='text'>test_title</title>
<category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/>
<category scheme='http://www.blogger.com/atom/ns#' term='test'/>
<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
<p>xxx<a href='http://www.google.com'>google</a><br/><img src='ddd.png'/></p>
<pre><code>
  def aaa
  end
</code></pre>
<p>end.</p></div></content></entry>
# 実際は code element 以外,改行なし
=end

# You can redistribute it and/or modify it under the same terms as Ruby.
require "rexml/document"
require 'time'

module BloggerContentDiv

  def setup_div
    ary = @entry.content.strip.lines.to_a
    return nil if ary.empty?
    ary.each_with_index{|x,i|
      to_tag(x)
      tag_p if ary.size == i + 1
    }
    return @div
  end

  def to_tag(x)
    on = {"<pre>"=>"pre","<blockquote>"=>"blockquote"}
    off = {"</pre>"=>true,"</blockquote>"=>true}
    if on[x.strip]
      tag_p unless @str_plain.empty?
      @tag = on[x.chop]
    elsif off[x.strip]
      my_tag
      @tag = nil
    else
      @str_plain << x unless @tag
      @str_tag << x if @tag
    end
  end

  private

  def tag_p
    str = @str_plain.strip
    return nil if str.empty?
    @e_p = @div.add_element("p")
    str.each_line{|w|
      @m = /<(a)|<(img)|<(del)/.match(w)
      @m ? sub_tag_p(w) : @e_p.add_text(w.strip)
      @e_p.add_element("br") if /\n/.match(w)
    }
    @str_plain = ""
    return @div
  end

  def sub_tag_p(line)
    pre_str unless @m.pre_match.empty?
    if @m[1] then tag_a(line)
    elsif @m[2] then tag_img(line)
    elsif @m[3] then tag_del(line)
    end
    s = /<.*?\/>/.match(line)
    post_str(s) if s
  end

  def tag_del(line)
    del = /<del>(.*?)<\/del>/.match(line)
    @e_p.add_element("del").add_text(del[1])
  end

  def tag_img(line)
    href = /<img\ssrc=["'](.*?)["']/.match(line)
    alt = /alt=["'](.*?)["']/.match(line)
    return nil unless href
    img = @e_p.add_element("img",{'src'=>href[1]})
    img.add_attribute({'alt'=>alt[1]}) if alt
  end

  def tag_a(line)
    all = /<a\shref=["'](.*?)["']>(.*?)<\/a>/.match(line)
    @e_p.add_element("a",{'href'=>all[1]}).add_text(all[2])
  end

  def pre_str
    @e_p.add_text(@m.pre_match.chop)
  end

  def post_str(s)
    @e_p.add_text(s.post_match.chop) 
  end

  def my_tag
    case @tag
      when "pre" then tag_pre
      when "blockquote" then tag_block
    end
    @str_tag = ""
  end

  def tag_pre
    @div.add_text("\n")
    str = @str_tag
    e1 = @div.add_element("pre")
    e2 = e1.add_element("code").add_text("\n")
    e2.add_text(str)
    @div.add_text("\n")
  end

  def tag_block
    e1 = @div.add_element("blockquote")
    e2 = e1.add_element("p")
    @str_tag.strip.each_line{|w|
      e2.add_text(w.strip)
      e2.add_element("br") if /\n/.match(w)
    }
  end

end

class BloggerEntry

  attr_reader :title, :content, :published, :category, :control
  attr_accessor :editid, :updated

  def initialize
    @published = nil
    @control = nil
    @title = nil
    @content = nil
    @category = nil
    # these value, after post request
    @editid = nil
    @updated = nil
  end

  def setup(h)
    h.each{|k, v|
      i = "@#{k}".downcase.to_sym
      set_ins(i, v) if i_defined?(i)
    }
    return self
  end

  def to_xml_post
    return BloggerXML.new(self).post_data
  end

  private

  def set_ins(i,v)
    self.instance_variable_set(i, v)
  end

  def i_defined?(i)
    self.instance_variable_defined?(i)
  end

end

class BloggerXML

  include BloggerContentDiv

  def initialize(entry)
    @entry = entry
    @str_plain = ""
    @str_tag = ""
    @tag = nil
  end

  def post_data
    doc = REXML::Document.new()
    doc << REXML::XMLDecl.new(version="1.0", encoding="utf-8" )
    # entry
    @e = doc.add_element("entry", {'xmlns'=>'http://www.w3.org/2005/Atom'})
    # published
    set_published
    # App control element
    set_control
    # Title
    @e.add_element("title", {'type'=>'text'}).add_text(@entry.title.strip)
    # Category
    set_category
    # Content
    content = @e.add_element("content", {'type'=>'xhtml'})
    @div = content.add_element("div", {'xmlns'=>'http://www.w3.org/1999/xhtml'})
    setup_div
   return @e
  end

  private

  def set_published
    unless @entry.published
      n = Time.now.iso8601.to_s
    else
      n = Time.parse(@entry.published).iso8601.to_s
    end
    @e.add_element("published").add_text(n.to_s)
  end

  def set_control
    if @entry.control
      ac = @e.add_element("app:control",
        {'xmlns:app'=>'http://www.w3.org/2007/app'})
      ac.add_element("app:draft").add_text("#{@entry.control}")
    end
  end

  def set_category
    @entry.category.split(",").to_a.each{|c|
      @e.add_element("category",{"scheme"=>'http://www.blogger.com/atom/ns#',  "term"=>"#{c}"})
    }
  end

end

#--- test
title = 'test_title'
content =<<EOF 
xxxx<a href='http://www.google.com'>google</a>
<img src='ddd.png' alt='fff'>
<pre>
   def aaa
   end
</pre>
end.
EOF

category = "Blogger,test"
control = "yes"
h = {:title=>title, :content=>content, :category=>category, :control=>control, :published=>'2009-06-01'}
entry = BloggerEntry.new().setup(h)
puts data = entry.to_xml_post

#--- Start Post
# require 'gdata'
#begin
#  blogID = 'xxxxxxxxxxxx'
#  url = "http://www.blogger.com/feeds/#{blogID}/posts/default"
#  client = GData::Client::Blogger.new
#  client.source = sourcename
#  clientlogin('username', 'password')
#  client.post(url, data.to_s)
#rescue GData::Client::AuthorizationError => e
#  print "gData error\n"
#  print e.message
#end

content =<<EOF
中の pre は本当は小文字 < >で囲まれてる

修正
100 行目あたり
def pre_str
@e_p.add_text(@m.pre_match.chop)
@e_p.add_text(@m.pre_match)
end

def post_str(s)
@e_p.add_text(s.post_match.chop)
@e_p.add_text(s.post_match)
end

0 件のコメント: