2005年11月22日

应用了ruby的mixin语法特性,WebUnit(SAX方式)、REXML、CSV库,代码如下:

require ‘webunit/webunit’
require ‘CSV’
require ‘rexml/document’
require ‘rexml/streamlistener’


include REXML


Response = WebUnit::TestCase::Response


# ################################
# 需要我们配置的项
# ################################


# 生成的CSV路径
$csv_file_path = ‘c:\test\ruby\data.csv’
# 要查询的数据
#$query_data = ‘GQNGSGKSSLLD’
$query_data = ‘tttggagtcctgtgtgcttctctctcttatggctgtgtccc’
# 首次进入的网址
$url = ‘http://www.test.com/test.cgi’


# #############################################################
# 修正WebUnit:遇到格式不正确的tag,原实现是抛异常,现改为简单忽略掉。
# 改写endtag和feed方法
# WebUnit安装方法:
# 下载地址:
# 下载后解压依次执行:
# cd 解压后的目录
# ruby install.rb config
# ruby install.rb setup
# ruby install.rb install
# #############################################################
module WebUnit
  class Parser < SGMLParser
    alias_method :o rigin_endtag,:endtag
    def endtag(tag)
      begin
        origin_endtag(tag)
      rescue
        return nil
      end
    end


    alias_method :o rigin_feed,:feed
    def feed(response)
      begin
        origin_feed(response)
      rescue
        return nil
      end
    end
  end
end


# #############################################################
# 使用WebUnit库,模拟用户浏览器上的操作:
# 1. 进入$url网址,在Search处输入要查询的数据_query,点提交按钮进入下一页
# 2. 将Format_Type下拉框选成"XML",点Format按钮进入下一页。
# 3. 如果显示的是html页面,源码中有Status=WAITING字串,则隔段时间重新提交表单,直至取到的是要的xml内容
# 4. 返回xml格式的字串
# #############################################################
def retrieve_content(_query)
  result = nil
  retry_interval = 3
  Response.reset
  # 进入首个页面
  response = Response::get($url)
  form = response.form
  # 输入Search后面的内容
  form.params['QUERY'].value = _query
  # 点按钮,进到下一页面
  response = form.submit
  # 该页显示The request
ID信息,将Format_type下拉框选成XML格式
  form = response.form
  form.params['FORMAT_TYPE'].value = ‘XML’
  #
提交表单,如果取到的内容包含Status=WAITING,隔段时间再试,直至取到真正要的xml内容
  content_ready = false
  while !content_ready do
    response = form.submit
    content_ready = ( response.body.index(‘Status=WAITING’)==nil )
    if(!content_ready) then
      sleep retry_interval
    else
      result = response.body
    end
  end


  #puts result
  puts ‘### retrieve content ok ###’
  return result
end


# #############################################################
# 以SAX方式解析xml(速度啊!用rexml的dom+xpath方式,慢死了)
# parse_xml_content 接收xml字串,
# 返回解析结果[[Hit_id_Value,Hit_def_Value,...], [],… ] 的形式
# #############################################################
Hit_attrs = ['Hit_id','Hit_def','Hit_len','Hsp_align-len',
        'Hsp_identity','Hsp_positive','Hsp_gaps','Hsp_query-from','Hsp_query-to',
        'Hsp_hit-from','Hsp_hit-to','Hsp_qseq','Hsp_hseq','Hsp_midline']


class ContentHandler
  include StreamListener
  attr_accessor :infos
  def initialize
    @infos = []
    @current_hit = nil
    @current_value = nil
    @hsp_num = 0
  end


  def tag_start(name, attributes)
    if name==’Hit’ then
      @current_hit = {}
      @hsp_num = 0
    end


    @hsp_num += 1 if name==’Hsp’
  end


  def tag_end(name)
    if name==’Hit’ then
      info = []
      Hit_attrs.each{ |key|
        info << @current_hit[key]
      }
      @infos << info
      @current_hit = nil
    end


    return if @hsp_num>1
    @current_hit[name] = @current_value if Hit_attrs.include?(name)
  end


  def text(text)
    @current_value = text
  end
end


def parse_xml_content(content)
  handler = ContentHandler.new
  Document.parse_stream(content, handler)
  # puts handler.infos
  puts ‘### parse xml ok ###’
  return handler.infos
end


# #############################################################
# 生成CSV文件
# 代码片段解析
# writer << ['a','b'] 会生成CSV的一行: a,b
# #############################################################


def generate_csv_file(csvFilePath,infos)
  CSV.open(csvFilePath,’w'){|writer|
    infos.each{|info|  writer << info  }
  }
  puts ‘### generate CSV file ok ###’
end


# #############################################################
# 定义main方法
# #############################################################


def __main__
  xml_content = retrieve_content($query_data)
  infos = parse_xml_content(xml_content)
  generate_csv_file($csv_file_path,infos)
  puts ‘### all completed ###’
end


# 执行main方法
__main__()