A Fast Ruby XML Builder
1 2 items = ['abc', 'def', 'ghi'] 3 xml = XML.new do 4 instruct! 5 reality(:time => Time.now) do 6 event do 7 type 1 8 path "/sharon" 9 value "abcdefg" 10 end 11 list.each {|i| item i} 12 end 13 puts xml.to_s
The XML class:
1 2 class XML 3 # blank slate 4 instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)} 5 6 # Each item in @doc is an array containing three values: type, value, attributes 7 8 def initialize(&block) 9 @doc = [] 10 instance_eval(&block) 11 end 12 13 def method_missing(tag, *args, &block) 14 value = block ? nil : args.pop 15 attributes = args.pop 16 @__to_s = nil # invalidate to_s cache 17 if value 18 @doc << [:open, tag, attributes] << [:value, value] << [:close, tag] 19 else 20 @doc << [:open, tag, attributes] 21 instance_eval(&block) 22 @doc << [:close, tag] 23 end 24 end 25 26 def instruct!(atts = nil) 27 @doc << [:instruct, atts || {:version => "1.0", :encoding => "UTF-8"}] 28 end 29 30 def to_s 31 @__to_s ||= @doc.map{|i| _fmt_part i}.join 32 end 33 34 alias_method :inspect, :to_s 35 36 def _fmt_part(part) 37 case part[0] 38 when :instruct 39 "<?xml #{_fmt_atts(part[1])}?>" 40 when :open 41 part[2] ? "<#{part[1]} #{_fmt_atts(part[2])}>" : 42 "<#{part[1]}>" 43 when :close 44 "</#{part[1]}>" 45 when :value 46 part[1].to_s 47 end 48 end 49 50 def _fmt_atts(atts) 51 atts.inject([]) {|m, i| m << "#{i[0]}=#{i[1].to_s.inspect}"}.join(' ') 52 end 53 end