M src/rexml/doctype.rb +2 -2
@@ 112,8 112,8 @@ module REXML
output << ' '
output << @name
output << " #@external_id" if @external_id
- output << " #@long_name" if @long_name
- output << " #@uri" if @uri
+ output << " #{@long_name.inspect}" if @long_name
+ output << " #{@uri.inspect}" if @uri
unless @children.empty?
next_indent = indent + 1
output << ' ['
M src/rexml/parsers/baseparser.rb +4 -4
@@ 53,7 53,7 @@ module REXML
STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um
ENTITY_START = /^\s*<!ENTITY/
- IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'].*?['"])?(\s+['"].*?["'])?/u
+ IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
ELEMENTDECL_START = /^\s*<!ELEMENT/um
ELEMENTDECL_PATTERN = /^\s*(<!ELEMENT.*?)>/um
SYSTEMENTITY = /^\s*(%.*?;)\s*$/um
@@ 217,10 217,10 @@ module REXML
close = md[2]
identity =~ IDENTITY
name = $1
- raise REXML::ParseException("DOCTYPE is missing a name") if name.nil?
+ raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil?
pub_sys = $2.nil? ? nil : $2.strip
- long_name = $3.nil? ? nil : $3.strip
- uri = $4.nil? ? nil : $4.strip
+ long_name = $4.nil? ? nil : $4.strip
+ uri = $6.nil? ? nil : $6.strip
args = [ :start_doctype, name, pub_sys, long_name, uri ]
if close == ">"
@document_status = :after_doctype
M src/rexml/parsers/sax2parser.rb +3 -1
@@ 94,6 94,8 @@ module REXML
when :end_document
handle( :end_document )
break
+ when :start_doctype
+ handle( :doctype, *event[1..-1])
when :end_doctype
context = context[1]
when :start_element
@@ 167,7 169,7 @@ module REXML
when :entitydecl
@entities[ event[1] ] = event[2] if event.size == 3
handle( *event )
- when :processing_instruction, :comment, :doctype, :attlistdecl,
+ when :processing_instruction, :comment, :attlistdecl,
:elementdecl, :cdata, :notationdecl, :xmldecl
handle( *event )
end
M test/sax.rb +67 -0
@@ 84,6 84,73 @@ class SAX2Tester < Test::Unit::TestCase
assert_equal 1, end_document
end
+
+
+ # used by test_simple_doctype_listener
+ # submitted by Jeff Barczewski
+ class SimpleDoctypeListener
+ include REXML::SAX2Listener
+ attr_reader :name, :pub_sys, :long_name, :uri
+
+ def initialize
+ @name = @pub_sys = @long_name = @uri = nil
+ end
+
+ def doctype(name, pub_sys, long_name, uri)
+ @name = name
+ @pub_sys = pub_sys
+ @long_name = long_name
+ @uri = uri
+ end
+ end
+
+ # test simple non-entity doctype in sax listener
+ # submitted by Jeff Barczewski
+ def test_simple_doctype_listener
+ xml = <<-END
+ <?xml version="1.0"?>
+ <!DOCTYPE greeting PUBLIC "Hello Greeting DTD" "http://foo/hello.dtd">
+ <greeting>Hello, world!</greeting>
+ END
+ parser = Parsers::SAX2Parser.new(xml)
+ dtl = SimpleDoctypeListener.new
+ parser.listen(dtl)
+ tname = nil
+ tpub_sys = nil
+ tlong_name = nil
+ turi = nil
+ parser.listen(:doctype) do |name, pub_sys, long_name, uri|
+ tname = name
+ tpub_sys = pub_sys
+ tlong_name = long_name
+ turi = uri
+ end
+ parser.parse
+ assert_equal 'greeting', tname, 'simple doctype block listener failed - incorrect name'
+ assert_equal 'PUBLIC', tpub_sys, 'simple doctype block listener failed - incorrect pub_sys'
+ assert_equal 'Hello Greeting DTD', tlong_name, 'simple doctype block listener failed - incorrect long_name'
+ assert_equal 'http://foo/hello.dtd', turi, 'simple doctype block listener failed - incorrect uri'
+ assert_equal 'greeting', dtl.name, 'simple doctype listener failed - incorrect name'
+ assert_equal 'PUBLIC', dtl.pub_sys, 'simple doctype listener failed - incorrect pub_sys'
+ assert_equal 'Hello Greeting DTD', dtl.long_name, 'simple doctype listener failed - incorrect long_name'
+ assert_equal 'http://foo/hello.dtd', dtl.uri, 'simple doctype listener failed - incorrect uri'
+ end
+
+ # test doctype with missing name, should throw ParseException
+ # submitted by Jeff Barczewseki
+ def test_doctype_with_mising_name_throws_exception
+ xml = <<-END
+ <?xml version="1.0"?>
+ <!DOCTYPE >
+ <greeting>Hello, world!</greeting>
+ END
+ parser = Parsers::SAX2Parser.new(xml)
+ assert_raise(REXML::ParseException, 'doctype missing name did not throw ParseException') do
+ parser.parse
+ end
+ end
+
+
class KouListener
include REXML::SAX2Listener
attr_accessor :sdoc, :edoc