1require "rexml/child" 2module REXML 3 module DTD 4 class EntityDecl < Child 5 START = "<!ENTITY" 6 START_RE = /^\s*#{START}/um 7 PUBLIC = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+PUBLIC\s+((["']).*?\3)\s+((["']).*?\5)\s*>/um 8 SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um 9 PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um 10 PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um 11 # <!ENTITY name SYSTEM "..."> 12 # <!ENTITY name "..."> 13 def initialize src 14 super() 15 md = nil 16 if src.match( PUBLIC ) 17 md = src.match( PUBLIC, true ) 18 @middle = "PUBLIC" 19 @content = "#{md[2]} #{md[4]}" 20 elsif src.match( SYSTEM ) 21 md = src.match( SYSTEM, true ) 22 @middle = "SYSTEM" 23 @content = md[2] 24 elsif src.match( PLAIN ) 25 md = src.match( PLAIN, true ) 26 @middle = "" 27 @content = md[2] 28 elsif src.match( PERCENT ) 29 md = src.match( PERCENT, true ) 30 @middle = "" 31 @content = md[2] 32 end 33 raise ParseException.new("failed Entity match", src) if md.nil? 34 @name = md[1] 35 end 36 37 def to_s 38 rv = "<!ENTITY #@name " 39 rv << "#@middle " if @middle.size > 0 40 rv << @content 41 rv 42 end 43 44 def write( output, indent ) 45 indent( output, indent ) 46 output << to_s 47 end 48 49 def EntityDecl.parse_source source, listener 50 md = source.match( PATTERN_RE, true ) 51 thing = md[0].squeeze(" \t\n\r") 52 listener.send inspect.downcase, thing 53 end 54 end 55 end 56end 57