diff -Nur ruby-2.5.8/test/rexml/parse/test_document_type_declaration.rb ruby-2.5.9/test/rexml/parse/test_document_type_declaration.rb
--- ruby-2.5.8/test/rexml/parse/test_document_type_declaration.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/parse/test_document_type_declaration.rb	2021-04-05 11:46:35.000000000 +0000
@@ -5,17 +5,187 @@
 module REXMLTests
   class TestParseDocumentTypeDeclaration < Test::Unit::TestCase
     private
-    def xml(internal_subset)
-      <<-XML
-<!DOCTYPE r SYSTEM "urn:x-rexml:test" [
-#{internal_subset}
-]>
+    def parse(doctype)
+      REXML::Document.new(<<-XML).doctype
+#{doctype}
 <r/>
       XML
     end
 
-    def parse(internal_subset)
-      REXML::Document.new(xml(internal_subset)).doctype
+    class TestName < self
+      def test_valid
+        doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r>
+        DOCTYPE
+        assert_equal("r", doctype.name)
+      end
+
+      def test_garbage_plus_before_name_at_line_start
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-DOCTYPE)
+<!DOCTYPE +
+r SYSTEM "urn:x-rexml:test" [
+]>
+          DOCTYPE
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed DOCTYPE: invalid name
+Line: 5
+Position: 51
+Last 80 unconsumed characters:
++ r SYSTEM "urn:x-rexml:test" [ ]>  <r/> 
+        DETAIL
+      end
+    end
+
+    class TestExternalID < self
+      class TestSystem < self
+        def test_left_bracket_in_system_literal
+          doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM "urn:x-rexml:[test" [
+]>
+          DOCTYPE
+          assert_equal([
+                         "r",
+                         "SYSTEM",
+                         nil,
+                         "urn:x-rexml:[test",
+                       ],
+                       [
+                         doctype.name,
+                         doctype.external_id,
+                         doctype.public,
+                         doctype.system,
+                       ])
+        end
+
+        def test_greater_than_in_system_literal
+          doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM "urn:x-rexml:>test" [
+]>
+          DOCTYPE
+          assert_equal([
+                         "r",
+                         "SYSTEM",
+                         nil,
+                         "urn:x-rexml:>test",
+                       ],
+                       [
+                         doctype.name,
+                         doctype.external_id,
+                         doctype.public,
+                         doctype.system,
+                       ])
+        end
+
+        def test_no_literal
+          exception = assert_raise(REXML::ParseException) do
+            parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM>
+            DOCTYPE
+          end
+          assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed DOCTYPE: system literal is missing
+Line: 3
+Position: 26
+Last 80 unconsumed characters:
+ SYSTEM>  <r/> 
+          DETAIL
+        end
+
+        def test_garbage_after_literal
+          exception = assert_raise(REXML::ParseException) do
+            parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM 'r.dtd'x'>
+            DOCTYPE
+          end
+          assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed DOCTYPE: garbage after external ID
+Line: 3
+Position: 36
+Last 80 unconsumed characters:
+x'>  <r/> 
+          DETAIL
+        end
+
+        def test_single_quote
+          doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM 'r".dtd'>
+          DOCTYPE
+          assert_equal("r\".dtd", doctype.system)
+        end
+
+        def test_double_quote
+          doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM "r'.dtd">
+          DOCTYPE
+          assert_equal("r'.dtd", doctype.system)
+        end
+      end
+
+      class TestPublic < self
+        class TestPublicIDLiteral < self
+          def test_content_double_quote
+            exception = assert_raise(REXML::ParseException) do
+              parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC 'double quote " is invalid' "r.dtd">
+              DOCTYPE
+            end
+            assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed DOCTYPE: invalid public ID literal
+Line: 3
+Position: 62
+Last 80 unconsumed characters:
+ PUBLIC 'double quote " is invalid' "r.dtd">  <r/> 
+            DETAIL
+          end
+
+          def test_single_quote
+            doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC 'public-id-literal' "r.dtd">
+            DOCTYPE
+            assert_equal("public-id-literal", doctype.public)
+          end
+
+          def test_double_quote
+            doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC "public'-id-literal" "r.dtd">
+            DOCTYPE
+            assert_equal("public'-id-literal", doctype.public)
+          end
+        end
+
+        class TestSystemLiteral < self
+          def test_garbage_after_literal
+            exception = assert_raise(REXML::ParseException) do
+              parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC 'public-id-literal' 'system-literal'x'>
+              DOCTYPE
+            end
+            assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed DOCTYPE: garbage after external ID
+Line: 3
+Position: 65
+Last 80 unconsumed characters:
+x'>  <r/> 
+           DETAIL
+          end
+
+          def test_single_quote
+            doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC "public-id-literal" 'system"-literal'>
+            DOCTYPE
+            assert_equal("system\"-literal", doctype.system)
+          end
+
+          def test_double_quote
+            doctype = parse(<<-DOCTYPE)
+<!DOCTYPE r PUBLIC "public-id-literal" "system'-literal">
+            DOCTYPE
+            assert_equal("system'-literal", doctype.system)
+          end
+        end
+      end
     end
 
     class TestMixed < self
@@ -45,6 +215,15 @@
         assert_equal([REXML::NotationDecl, REXML::AttlistDecl],
                      doctype.children.collect(&:class))
       end
+
+      private
+      def parse(internal_subset)
+        super(<<-DOCTYPE)
+<!DOCTYPE r SYSTEM "urn:x-rexml:test" [
+#{internal_subset}
+]>
+        DOCTYPE
+      end
     end
   end
 end
diff -Nur ruby-2.5.8/test/rexml/parse/test_element.rb ruby-2.5.9/test/rexml/parse/test_element.rb
--- ruby-2.5.8/test/rexml/parse/test_element.rb	1970-01-01 00:00:00.000000000 +0000
+++ ruby-2.5.9/test/rexml/parse/test_element.rb	2021-04-05 11:46:35.000000000 +0000
@@ -0,0 +1,77 @@
+require "test/unit"
+require "rexml/document"
+
+module REXMLTests
+  class TestParseElement < Test::Unit::TestCase
+    def parse(xml)
+      REXML::Document.new(xml)
+    end
+
+    class TestInvalid < self
+      def test_top_level_end_tag
+        exception = assert_raise(REXML::ParseException) do
+          parse("</a>")
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Unexpected top-level end tag (got 'a')
+Line: 1
+Position: 4
+Last 80 unconsumed characters:
+
+        DETAIL
+      end
+
+      def test_no_end_tag
+        exception = assert_raise(REXML::ParseException) do
+          parse("<a></")
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Missing end tag for 'a'
+Line: 1
+Position: 5
+Last 80 unconsumed characters:
+</
+        DETAIL
+      end
+
+      def test_empty_namespace_attribute_name
+        exception = assert_raise(REXML::ParseException) do
+          parse("<x :a=\"\"></x>")
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Invalid attribute name: <:a="">
+Line: 1
+Position: 13
+Last 80 unconsumed characters:
+
+        DETAIL
+      end
+
+      def test_garbage_less_than_before_root_element_at_line_start
+        exception = assert_raise(REXML::ParseException) do
+          parse("<\n<x/>")
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+malformed XML: missing tag start
+Line: 2
+Position: 6
+Last 80 unconsumed characters:
+< <x/>
+        DETAIL
+      end
+
+      def test_garbage_less_than_slash_before_end_tag_at_line_start
+        exception = assert_raise(REXML::ParseException) do
+          parse("<x></\n</x>")
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Missing end tag for 'x'
+Line: 2
+Position: 10
+Last 80 unconsumed characters:
+</ </x>
+        DETAIL
+      end
+    end
+  end
+end
diff -Nur ruby-2.5.8/test/rexml/parse/test_notation_declaration.rb ruby-2.5.9/test/rexml/parse/test_notation_declaration.rb
--- ruby-2.5.8/test/rexml/parse/test_notation_declaration.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/parse/test_notation_declaration.rb	2021-04-05 11:46:35.000000000 +0000
@@ -23,10 +23,100 @@
         doctype = parse("<!NOTATION name PUBLIC 'urn:public-id'>")
         assert_equal("name", doctype.notation("name").name)
       end
+
+      def test_no_name
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: name is missing
+Line: 5
+Position: 72
+Last 80 unconsumed characters:
+ <!NOTATION>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_invalid_name
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION '>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: invalid name
+Line: 5
+Position: 74
+Last 80 unconsumed characters:
+'>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_no_id_type
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION name>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: invalid ID type
+Line: 5
+Position: 77
+Last 80 unconsumed characters:
+>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_invalid_id_type
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION name INVALID>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: invalid ID type
+Line: 5
+Position: 85
+Last 80 unconsumed characters:
+ INVALID>  ]> <r/> 
+        DETAIL
+      end
     end
 
     class TestExternalID < self
       class TestSystem < self
+        def test_no_literal
+          exception = assert_raise(REXML::ParseException) do
+            parse(<<-INTERNAL_SUBSET)
+<!NOTATION name SYSTEM>
+            INTERNAL_SUBSET
+          end
+          assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: system literal is missing
+Line: 5
+Position: 84
+Last 80 unconsumed characters:
+ SYSTEM>  ]> <r/> 
+          DETAIL
+        end
+
+        def test_garbage_after_literal
+          exception = assert_raise(REXML::ParseException) do
+            parse(<<-INTERNAL_SUBSET)
+<!NOTATION name SYSTEM 'system-literal'x'>
+            INTERNAL_SUBSET
+          end
+          assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: garbage before end >
+Line: 5
+Position: 103
+Last 80 unconsumed characters:
+x'>  ]> <r/> 
+          DETAIL
+        end
+
         def test_single_quote
           doctype = parse(<<-INTERNAL_SUBSET)
 <!NOTATION name SYSTEM 'system-literal'>
@@ -44,6 +134,21 @@
 
       class TestPublic < self
         class TestPublicIDLiteral < self
+          def test_content_double_quote
+            exception = assert_raise(REXML::ParseException) do
+              parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC 'double quote " is invalid' "system-literal">
+              INTERNAL_SUBSET
+            end
+            assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: invalid public ID literal
+Line: 5
+Position: 129
+Last 80 unconsumed characters:
+ PUBLIC 'double quote " is invalid' "system-literal">  ]> <r/> 
+            DETAIL
+          end
+
           def test_single_quote
             doctype = parse(<<-INTERNAL_SUBSET)
 <!NOTATION name PUBLIC 'public-id-literal' "system-literal">
@@ -60,6 +165,21 @@
         end
 
         class TestSystemLiteral < self
+          def test_garbage_after_literal
+            exception = assert_raise(REXML::ParseException) do
+              parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC 'public-id-literal' 'system-literal'x'>
+              INTERNAL_SUBSET
+            end
+            assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: garbage before end >
+Line: 5
+Position: 123
+Last 80 unconsumed characters:
+x'>  ]> <r/> 
+           DETAIL
+          end
+
           def test_single_quote
             doctype = parse(<<-INTERNAL_SUBSET)
 <!NOTATION name PUBLIC "public-id-literal" 'system-literal'>
@@ -96,5 +216,66 @@
         end
       end
     end
+
+    class TestPublicID < self
+      def test_no_literal
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: public ID literal is missing
+Line: 5
+Position: 84
+Last 80 unconsumed characters:
+ PUBLIC>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_literal_content_double_quote
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC 'double quote " is invalid in PubidLiteral'>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: invalid public ID literal
+Line: 5
+Position: 128
+Last 80 unconsumed characters:
+ PUBLIC 'double quote \" is invalid in PubidLiteral'>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_garbage_after_literal
+        exception = assert_raise(REXML::ParseException) do
+          parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC 'public-id-literal'x'>
+          INTERNAL_SUBSET
+        end
+        assert_equal(<<-DETAIL.chomp, exception.to_s)
+Malformed notation declaration: garbage before end >
+Line: 5
+Position: 106
+Last 80 unconsumed characters:
+x'>  ]> <r/> 
+        DETAIL
+      end
+
+      def test_literal_single_quote
+        doctype = parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC 'public-id-literal'>
+        INTERNAL_SUBSET
+        assert_equal("public-id-literal", doctype.notation("name").public)
+      end
+
+      def test_literal_double_quote
+        doctype = parse(<<-INTERNAL_SUBSET)
+<!NOTATION name PUBLIC "public-id-literal">
+        INTERNAL_SUBSET
+        assert_equal("public-id-literal", doctype.notation("name").public)
+      end
+    end
   end
 end
diff -Nur ruby-2.5.8/test/rexml/parser/test_tree.rb ruby-2.5.9/test/rexml/parser/test_tree.rb
--- ruby-2.5.8/test/rexml/parser/test_tree.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/parser/test_tree.rb	2021-04-05 11:46:35.000000000 +0000
@@ -12,7 +12,7 @@
         parse(xml)
       end
       assert_equal(<<-MESSAGE, exception.to_s)
-Missing end tag for 'root' (got "not-root")
+Missing end tag for 'root' (got 'not-root')
 Line: 1
 Position: #{xml.bytesize}
 Last 80 unconsumed characters:
diff -Nur ruby-2.5.8/test/rexml/parser/test_ultra_light.rb ruby-2.5.9/test/rexml/parser/test_ultra_light.rb
--- ruby-2.5.8/test/rexml/parser/test_ultra_light.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/parser/test_ultra_light.rb	2021-04-05 11:46:35.000000000 +0000
@@ -16,7 +16,6 @@
                        nil,
                        [:entitydecl, "name", "value"]
                      ],
-                     [:text, "\n"],
                      [:start_element, :parent, "root", {}],
                      [:text, "\n"],
                    ],
diff -Nur ruby-2.5.8/test/rexml/test_core.rb ruby-2.5.9/test/rexml/test_core.rb
--- ruby-2.5.8/test/rexml/test_core.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/test_core.rb	2021-04-05 11:46:35.000000000 +0000
@@ -1,4 +1,4 @@
-# coding: binary
+# coding: utf-8
 # frozen_string_literal: false
 
 require_relative "rexml_test_utils"
@@ -995,7 +995,7 @@
       document.write(s)
 
       ## XML Doctype
-      str = '<!DOCTYPE foo "bar">'
+      str = '<!DOCTYPE foo SYSTEM "bar">'
       source  = REXML::Source.new(str)
       doctype = REXML::DocType.new(source)
       document.add(doctype)
@@ -1274,14 +1274,15 @@
 
     def test_ticket_21
       src = "<foo bar=value/>"
-      assert_raise( ParseException, "invalid XML should be caught" ) {
+      exception = assert_raise(ParseException) do
         Document.new(src)
-      }
-      begin
-        Document.new(src)
-      rescue
-        assert_match( /missing attribute quote/, $!.message )
       end
+      assert_equal(<<-DETAIL, exception.to_s)
+Missing attribute value start quote: <bar>
+Line: 1
+Position: 16
+Last 80 unconsumed characters:
+      DETAIL
     end
 
     def test_ticket_63
diff -Nur ruby-2.5.8/test/rexml/test_doctype.rb ruby-2.5.9/test/rexml/test_doctype.rb
--- ruby-2.5.8/test/rexml/test_doctype.rb	2020-03-31 12:15:56.000000000 +0000
+++ ruby-2.5.9/test/rexml/test_doctype.rb	2021-04-05 11:46:35.000000000 +0000
@@ -4,65 +4,111 @@
 
 module REXMLTests
   class TestDocTypeAccessor < Test::Unit::TestCase
-
     def setup
       @sysid = "urn:x-test:sysid1"
-      @notid1 = "urn:x-test:notation1"
-      @notid2 = "urn:x-test:notation2"
-      document_string1 = <<-"XMLEND"
-      <!DOCTYPE r SYSTEM "#{@sysid}" [
-        <!NOTATION n1 SYSTEM "#{@notid1}">
-        <!NOTATION n2 SYSTEM "#{@notid2}">
+      @notation_id1 = "urn:x-test:notation1"
+      @notation_id2 = "urn:x-test:notation2"
+      xml_system = <<-XML
+      <!DOCTYPE root SYSTEM "#{@sysid}" [
+        <!NOTATION n1 SYSTEM "#{@notation_id1}">
+        <!NOTATION n2 SYSTEM "#{@notation_id2}">
       ]>
-      <r/>
-      XMLEND
-      @doctype1 = REXML::Document.new(document_string1).doctype
+      <root/>
+      XML
+      @doc_type_system = REXML::Document.new(xml_system).doctype
 
       @pubid = "TEST_ID"
-      document_string2 = <<-"XMLEND"
-      <!DOCTYPE r PUBLIC "#{@pubid}">
-      <r/>
-      XMLEND
-      @doctype2 = REXML::Document.new(document_string2).doctype
-
-      document_string3 = <<-"XMLEND"
-      <!DOCTYPE r PUBLIC "#{@pubid}" "#{@sysid}">
-      <r/>
-      XMLEND
-      @doctype3 = REXML::Document.new(document_string3).doctype
-
+      xml_public_system = <<-XML
+      <!DOCTYPE root PUBLIC "#{@pubid}" "#{@sysid}">
+      <root/>
+      XML
+      @doc_type_public_system = REXML::Document.new(xml_public_system).doctype
     end
 
     def test_public
-      assert_equal(nil, @doctype1.public)
-      assert_equal(@pubid, @doctype2.public)
-      assert_equal(@pubid, @doctype3.public)
+      assert_equal([
+                     nil,
+                     @pubid,
+                   ],
+                   [
+                     @doc_type_system.public,
+                     @doc_type_public_system.public,
+                   ])
+    end
+
+    def test_to_s
+      assert_equal("<!DOCTYPE root PUBLIC \"#{@pubid}\" \"#{@sysid}\">",
+                   @doc_type_public_system.to_s)
     end
 
     def test_system
-      assert_equal(@sysid, @doctype1.system)
-      assert_equal(nil, @doctype2.system)
-      assert_equal(@sysid, @doctype3.system)
+      assert_equal([
+                     @sysid,
+                     @sysid,
+                   ],
+                   [
+                     @doc_type_system.system,
+                     @doc_type_public_system.system,
+                   ])
     end
 
     def test_notation
-      assert_equal(@notid1, @doctype1.notation("n1").system)
-      assert_equal(@notid2, @doctype1.notation("n2").system)
+      assert_equal([
+                     @notation_id1,
+                     @notation_id2,
+                   ],
+                   [
+                     @doc_type_system.notation("n1").system,
+                     @doc_type_system.notation("n2").system,
+                   ])
     end
 
     def test_notations
-      notations = @doctype1.notations
-      assert_equal(2, notations.length)
-      assert_equal(@notid1, find_notation(notations, "n1").system)
-      assert_equal(@notid2, find_notation(notations, "n2").system)
+      notations = @doc_type_system.notations
+      assert_equal([
+                     @notation_id1,
+                     @notation_id2,
+                   ],
+                   notations.collect(&:system))
     end
+  end
 
-    def find_notation(notations, name)
-      notations.find { |notation|
-        name == notation.name
-      }
+  class TestDocType < Test::Unit::TestCase
+    class TestExternalID < self
+      class TestSystem < self
+        class TestSystemLiteral < self
+          def test_to_s
+            doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root.dtd"])
+            assert_equal("<!DOCTYPE root SYSTEM \"root.dtd\">",
+                         doctype.to_s)
+          end
+        end
+      end
+
+      class TestPublic < self
+        class TestPublicIDLiteral < self
+          def test_to_s
+            doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
+            assert_equal("<!DOCTYPE root PUBLIC \"pub\" \"root.dtd\">",
+                         doctype.to_s)
+          end
+        end
+
+        class TestSystemLiteral < self
+          def test_to_s
+            doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
+            assert_equal("<!DOCTYPE root PUBLIC \"pub\" \"root.dtd\">",
+                         doctype.to_s)
+          end
+
+          def test_to_s_double_quote
+            doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root\".dtd"])
+            assert_equal("<!DOCTYPE root PUBLIC \"pub\" 'root\".dtd'>",
+                         doctype.to_s)
+          end
+        end
+      end
     end
-
   end
 
   class TestNotationDeclPublic < Test::Unit::TestCase
@@ -77,11 +123,26 @@
                    decl(@id, nil).to_s)
     end
 
+    def test_to_s_pubid_literal_include_apostrophe
+      assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}'\">",
+                   decl("#{@id}'", nil).to_s)
+    end
+
     def test_to_s_with_uri
       assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" \"#{@uri}\">",
                    decl(@id, @uri).to_s)
     end
 
+    def test_to_s_system_literal_include_apostrophe
+      assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" \"system'literal\">",
+                   decl(@id, "system'literal").to_s)
+    end
+
+    def test_to_s_system_literal_include_double_quote
+      assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" 'system\"literal'>",
+                   decl(@id, "system\"literal").to_s)
+    end
+
     private
     def decl(id, uri)
       REXML::NotationDecl.new(@name, "PUBLIC", id, uri)
@@ -99,9 +160,19 @@
                    decl(@id).to_s)
     end
 
+    def test_to_s_include_apostrophe
+      assert_equal("<!NOTATION #{@name} SYSTEM \"#{@id}'\">",
+                   decl("#{@id}'").to_s)
+    end
+
+    def test_to_s_include_double_quote
+      assert_equal("<!NOTATION #{@name} SYSTEM '#{@id}\"'>",
+                   decl("#{@id}\"").to_s)
+    end
+
     private
     def decl(id)
-      REXML::NotationDecl.new(@name, "SYSTEM", id, nil)
+      REXML::NotationDecl.new(@name, "SYSTEM", nil, id)
     end
   end
 end
