วันพฤหัสบดี, สิงหาคม 28, 2551

ruby XML

วันก่อนเขียน SAX Parser ด้วย Ruby สำหรับ

Leximac

ผมสร้าง class ขึ้นมา 3 ไฟล์ ไฟล์แรกเป็นการสั้งให้ Sax ทำการอ่านไฟล์ และเป็นตัวบอกว่าอ่านแล้วให้ไปเรียก method ใน Object ไหน

#sax_parser.rb 
require 'rubygems' 
require 'xml/libxml' 
require 'handler'  

class SaxParser   

def initialize(xml)
  @parser = XML::SaxParser.new    
  @parser.string = xml    
  @parser.callbacks = Handler.new   
end

def parse     
  @parser.parse    
  @parser.callbacks.elements   
end 

end 

ไฟล์ Sax Parser จะอ่าน xml ทีละ element แล้วมาเรียก method ใน Handler ตาม XML ที่อ่านได้ สามตัว

* start element
* character
* end element

character มันทำตัวสมชื่อทีเดียวครับ อ่านมาทีละตัวอักษรจริงๆ ต้องเอามาต่อๆ กันเอาเอง

# handler.rb 

require 'word'  

class Handler   
attr_accessor :elements, :current_element    

def initialize     
  @elements = []     
  @@word = Word.new   
end    

def on_start_element(element, attributes)     
  @current_element = element     
  if element == 'Doc'       
    @@word = Word.new     
  end     
  if element =='dictionary'       
    print xml_header     
  end 
end    

def on_characters(characters = '')     
  case @current_element      
  when "id"       
    @@word.unique_id << characters      
  when "ecat"       
    @@word.english_category << characters      
  when "esearch"       
    @@word.english_search << characters      
  when "eentry"       
    @@word.english_entry << characters      
  when "tentry"       
    @@word.thai_entry << characters      
  when "esyn"       
    @@word.english_sync << characters      
  when "ethai"       
    @@word.english_thai << characters     
  end   
end    

def on_end_element(element)     
  @current_element = nil     
  if element == "Doc"       
    print @@word.to_xml       
    @@word = nil     
  end     
  if element == "dictionary"       
    print xml_button     
  end   
end    

def method_missing(method_name, *attributes, &block)   
end    

def xml_header       
  # string for xml header   
end     

def xml_buttom      
  # string for xml buttom   
end 

end 

ผมแยก Object Word ออกมาจากตัว handler เพราะอยากได้ลูกน้องในการเขียนโปรแกรม อยากฝึกให้ Word มันเก่งที่สุดในเรื่องของมัน handler จะได้คิดน้อยลง ต่อไปน่าจะเก่งขนาดคิดถึงความสัมพันธ์ของ word หรือเก่งถึงขั้น insert ข้อมูลลง database ได้เลยทีเดียว


class Word    
  attr_accessor :english_search, :english_entry, :thai_entry, :english_category,
                :english_sync, :english_thai, :unique_id    

def initialize     
  @english_search = []     
  @english_entry = []     
  @thai_entry = []     
  @english_category = []     
  @english_sync = []     
  @english_thai = []     
  @unique_id = []     
  Array   
end    

def to_xml     
  id = english_search.to_s.gsub(' ','_')     
  xml = "<d:entry d:title="\"#{english_search}\"" 
  id="\"#{id}_#{unique_id}\"">\n"     
  xml += "  <d:index d:value="\"#{english_entry}\"/">\n"     
  xml += "  <span class="entry">#{english_entry}\n"     
  xml += "  <span class="category">(#{english_category})\n"     
  xml += "  <div class="\"thai_entry\"">#{thai_entry}</div>\n" 

  unless thai_entry.empty?     
    xml += "  <div class="\"english_thai\""><span class="label">
              คำเหมือน :</span><span class="words"> 
              #{english_thai}</span></div>\n" 
  unless english_thai.empty?     
    xml += "  <div class="\"english_sync\"">
              <span class="label">คำเหมือน :</span><span class="words">           
              #{english_sync}</span></div>\n" 
  unless english_sync.empty?     
    xml += "\n"   
end 
end 


ไฟล์สุดท้ายไม่ค่อยเกี่ยวเท่าไหรครับ เอาไว้เรียกใช้สามไฟล์ข้างบน

require 'sax_parser'  
xml = open(ARGV[0], 'r').collect { |l| l }.join puts SaxParser.new(xml).parse 

ใน blog ตัวอย่าง Sax Parser บอกว่า libxml เร็วกว่า EXML ที่เป็น default ของ Ruby ซะอีก หลังจากที่ได้ลองกับ XML ของ Lexitron จัดว่าประทับใจทีเดียวครับ

ที่มา -- lucaguidi.com
blog comments powered by Disqus