require "ev/tree" class SGMLObject < TreeObject def to_s res = "" parsetree("prechildren_to_s", "postchildren_to_s", res) res end def to_h res = "" parsetree("prechildren_to_sgml", "postchildren_to_sgml", res) res end end class Text < SGMLObject def initialize(text) super() @text = text end def prechildren_to_s(res) #res << "#{CGI.unescapeHTML(@text)} " res << @text end def prechildren_to_sgml(res) #res << "#{CGI.unescapeHTML(@text)}" res << @text end end class Comment < SGMLObject def initialize(text) super() @text = text end def prechildren_to_sgml(res) res << "#{@text}" end end class Special < SGMLObject def initialize(text) super() @text = text end def prechildren_to_sgml(res) res << "#{@text}" end end class Instruction < SGMLObject def initialize(text) super() @text = text end def prechildren_to_sgml(res) res << "#{@text}" end end class Tag < SGMLObject attr_reader :args attr_writer :args def initialize(subtype, args={}) super(subtype) @args = args @text = "" end end class OpenTag < Tag def initialize(*args) super @upordown = Down end def prechildren_to_sgml(res) a = [@subtype] @args.each do |k, v| if not v.include?("'") a << "#{k}='#{v}'" else if not v.include?('"') a << "#{k}=\"#{v}\"" else a << "#{k}='#{v.gsub(/\'/, '"')}'" end end end res << "<#{a.join(" ")}>" + @text end def postchildren_to_sgml(res) res << "" if @closed end end class CloseTag < Tag def initialize(*args) super @upordown = Dummy end end class SGML < Tree def initialize(*args) @tagcache = {} super end def buildobjects(string) @objects = [] verwerk3 = lambda do |string| a = [] string[1..-2].splitblocks(["'", "'"], ['"', '"']).collect do |type, s| case type when 0 if self.class.to_s == "HTML" s.splitwords.each do |w| d = w.split("=", 2) if d.length == 1 a << d[0] else a << d[0] if not d[0].nil? and not d[0].empty? a << "=" a << d[1] if not d[1].nil? and not d[1].empty? end end else a.concat s.splitwords(["/", "="]) end when 1, 2 then a << s end end open = false close = false a = a[0].splitwords("/") + a[1..-1] if a[0] == "/" close = true a.shift else open = true end if a[-1] == "/" close = true a.pop end tag = a.shift.downcase args = {} while not a.length.zero? if a.length >= 3 and a[1] == "=" key = a.shift.downcase dummy = a.shift value = a.shift.noquotes args[key] = value else key = a.shift.downcase args[key] = "" end end [tag, args, open, close] end verwerk2 = lambda do |string| if @tagcache.include? string res = @tagcache[string] else res = verwerk3.call(string) @tagcache[string] = res end res end verwerk1 = lambda do |string| tag, args, open, close = verwerk2.call(string) @objects << OpenTag.new(tag.dup, args.dup) if open @objects << CloseTag.new(tag.dup, args.dup) if close end string.splitblocks([""], [""], [""], ["<", ">"]).each do |type, s| case type when 0 then @objects << Text.new(s) when 1 then @objects << Comment.new(s) when 2 then @objects << Special.new(s) when 3 then @objects << Instruction.new(s) when 4 then verwerk1.call(s) end end end def to_s res = "" parsetree("prechildren_to_s", "postchildren_to_s", res) res end def to_h res = "" parsetree("prechildren_to_sgml", "postchildren_to_sgml", res) res end end