Index: test/xpath_test.rb
===================================================================
--- test/xpath_test.rb	(revision 1287)
+++ test/xpath_test.rb	(working copy)
@@ -335,7 +335,7 @@
 			fail "'bar' should match nothing in this case"
 		}
 
-		namespace = {"t","this"}
+		namespace = {"t"=>"this"}
 		results = XPath.first( doc, "//t:bar", namespace )
 		assert_equal "this bar", results.text
 	end
@@ -937,7 +937,7 @@
     sum = Document.new(File.new("test/yahoo.xml")).elements.to_a("//item").size
     assert_equal( 10, sum )
 
-    text = Document.new(File.new("test/yahoo.xml")).elements.to_a(%Q{//title[contains(text(), "'")]}).collect{|e| e.text}.to_s
+    text = Document.new(File.new("test/yahoo.xml")).elements.to_a(%Q{//title[contains(text(), "'")]}).collect{|e| e.text}.join
     assert_equal( "Broward labor market's a solid performer (Miami Herald)", text )
   end
 
Index: test/changing_encoding.rb
===================================================================
--- test/changing_encoding.rb	(revision 1287)
+++ test/changing_encoding.rb	(working copy)
@@ -1,4 +1,5 @@
 #!/usr/bin/ruby -Ku
+# -*- coding: utf-8 -*-
 
 require 'kconv'
 require 'iconv'
Index: test/contrib_test.rb
===================================================================
--- test/contrib_test.rb	(revision 1287)
+++ test/contrib_test.rb	(working copy)
@@ -90,7 +90,7 @@
 		assert_equal "myprog-config", doc.root.name
 		count = 0
 		REXML::XPath.each(doc, "x:myprog-config/x:main/x:parameter", 
-			{"x","http://someurl/program/version"}) { |element|
+			{"x"=>"http://someurl/program/version"}) { |element|
 				assert_equal "name", element.attributes["name"]
 			count += 1;
 		}
@@ -227,6 +227,9 @@
   def test_umlaut
 		koln_iso = 'Köln'
 		koln_utf = 'KÃ¶ln'
+                if koln_utf.respond_to? :force_encoding
+                  koln_utf.force_encoding(Encoding::UTF_8)
+                end
     source_iso = "<?xml version='1.0' encoding='ISO-8859-1'?><test>#{koln_iso}</test>"
     source_utf = "<?xml version='1.0' encoding='UTF-8'?><test>#{koln_utf}</test>"
 		doc = REXML::Document.new(source_iso)
@@ -255,16 +258,22 @@
 </intranet>
 EOF
 		tn = XPath.first(doc, "//nebenspalte/text()[2]")
-		assert_equal("Nützliches von Flashern für Flasher.".unpack('C*').pack('U*'), tn.to_s.strip)
+		expected_iso = "Nützliches von Flashern für Flasher."
+                expected_utf = expected_iso.unpack('C*').pack('U*')
+                if expected_utf.respond_to? :encode
+		  expected_iso.force_encoding("iso-8859-1")
+		  expected_utf.force_encoding(Encoding::UTF_8)
+                end
+		assert_equal(expected_utf, tn.to_s.strip)
     f = REXML::Formatters::Default.new
     f.write( tn, Output.new(o = "", "ISO-8859-1") )
-		assert_equal("Nützliches von Flashern für Flasher.", o.strip)
+		assert_equal(expected_iso, o.strip)
 
 		doc = Document.new File.new('test/xmlfile-bug.xml')
 		tn = XPath.first(doc, "//nebenspalte/text()[2]")
-		assert_equal("Nützliches von Flashern für Flasher.".unpack('C*').pack('U*'), tn.to_s.strip)
+		assert_equal(expected_utf, tn.to_s.strip)
     f.write( tn, Output.new(o = "", "ISO-8859-1") )
-		assert_equal("Nützliches von Flashern für Flasher.", o.strip)
+		assert_equal(expected_iso, o.strip)
   end
 
 	def test_element_cloning_namespace_Chris
Index: test/jaxen.rb
===================================================================
--- test/jaxen.rb	(revision 1287)
+++ test/jaxen.rb	(working copy)
@@ -65,7 +65,8 @@
     got = XPath.match( ctx, valueOfElement.attributes["select"], namespaces, variables )[0]
     assert_true( (got.nil? && expected.nil?) || !got.nil? )
     case got.class
-    when Element          : assert_equal( got.class, Element )
+    when Element
+      assert_equal( got.class, Element )
     when Attribute, Text, Comment, TrueClass, FalseClass
       assert_equal( expected, got.to_s )
     when Instruction
Index: test/entity.rb
===================================================================
--- test/entity.rb	(revision 1287)
+++ test/entity.rb	(working copy)
@@ -141,4 +141,8 @@
 		assert_equal("&amp;", REXML::Text.new("&amp;", false, nil, true).to_s)
 		#assert_equal("&", REXML::Text.new("&amp;", false, false).to_s)
 	end
+
+	def test_single_pass_unnormalization
+		assert_equal '&amp;&', REXML::Text::unnormalize('&#38;amp;&amp;')
+	end
 end
Index: test/preceding-sibling.rb
===================================================================
--- test/preceding-sibling.rb	(revision 1287)
+++ test/preceding-sibling.rb	(working copy)
@@ -25,7 +25,7 @@
   def test_Dd_preceding_sibling_children
     arr = []
     XPath.each(@@docDd, "//b[@x='ab02A']/preceding-sibling::b/child::*") do |cell|
-      arr << cell.texts.to_s
+      arr << cell.texts.join
     end
     assert_equal( 'Success', arr.join )
   end
Index: test/listenertest.rb
===================================================================
--- test/listenertest.rb	(revision 1287)
+++ test/listenertest.rb	(working copy)
@@ -83,7 +83,11 @@
 <f  a="é" />
 </g>'
 		doc = REXML::Document.new( source )
-		assert_equal( 'Ã©', doc.elements['/g/f'].attributes['a'] )
+		a = doc.elements['/g/f'].attribute('a')
+                if a.value.respond_to? :force_encoding
+                  a.value.force_encoding('binary')
+                end
+		assert_equal( 'Ã©', a.value)
 		doc = REXML::Document.parse_stream(
 			File::new("test/stream_accents.xml"),
 			AccentListener::new
Index: test/attributes.rb
===================================================================
--- test/attributes.rb	(revision 1287)
+++ test/attributes.rb	(working copy)
@@ -187,4 +187,10 @@
     d.root.context[:attribute_quote] = :quote
     assert_equal( %q{<a x="1" y="2"><b z="3"/></a>}, d.to_s )
   end
+
+  def test_ticket_127
+    doc = Document.new
+    doc.add_element 'a', { 'v' => 'x & y' }
+    assert doc.to_s.index(';')
+  end
 end
Index: test/encoding.rb
===================================================================
--- test/encoding.rb	(revision 1287)
+++ test/encoding.rb	(working copy)
@@ -17,6 +17,7 @@
 	def test_encoded_in_encoded_out
     doc = Document.new( @encoded )
     doc.write( out="" )
+    out.force_encoding('binary') if out.respond_to? :force_encoding
     assert_equal( @encoded, out )
   end
 
@@ -28,6 +29,7 @@
     REXML::Formatters::Default.new.write( doc.root, out="" )
     assert_equal( @not_encoded, out )
     char = XPath.first( doc, "/a/b/text()" ).to_s
+    char.force_encoding('binary') if char.respond_to? :force_encoding
     assert_equal( "Ä‰", char )
   end
 
@@ -44,6 +46,7 @@
     doc.xml_decl.encoding = "ISO-8859-3"
     assert_equal( doc.encoding, "ISO-8859-3" )
     doc.write( out="" )
+    out.force_encoding('binary') if out.respond_to? :force_encoding
     assert_equal( @encoded, out )
   end
 
@@ -51,6 +54,7 @@
   def test_in_different_out
     doc = Document.new( @not_encoded )
     doc.write( Output.new( out="", "ISO-8859-3" ) )
+    out.force_encoding('binary') if out.respond_to? :force_encoding
     assert_equal( @encoded, out )
   end
 
@@ -61,8 +65,10 @@
     <?xml version='1.0' encoding='ISO-8859-1'?>
     <a a="ÿ">ÿ</a>
     EOL
-    assert_equal( doc.elements['a'].attributes['a'], "\303\277" )
-    assert_equal( doc.elements['a'].text, "\303\277" )
+    expect = "\303\277"
+    expect.force_encoding('UTF-8') if expect.respond_to? :force_encoding
+    assert_equal( expect, doc.elements['a'].attributes['a'] )
+    assert_equal( expect, doc.elements['a'].text )
   end
 
 
Index: test/core_test.rb
===================================================================
--- test/core_test.rb	(revision 1287)
+++ test/core_test.rb	(working copy)
@@ -656,8 +656,12 @@
     koln_utf8 = "K\xc3\xb6ln"
     source = Source.new( koln_iso_8859_1, 'iso-8859-1' )
     results = source.scan(/.*/)[0]
+    koln_utf8.force_encoding('UTF-8') if koln_utf8.respond_to?(:force_encoding)
     assert_equal koln_utf8, results
     output << results
+    if koln_iso_8859_1.respond_to?(:force_encoding)
+      koln_iso_8859_1.force_encoding('ISO-8859-1')
+    end
     assert_equal koln_iso_8859_1, out
   end
 
Index: test/sax.rb
===================================================================
--- test/sax.rb	(revision 1287)
+++ test/sax.rb	(working copy)
@@ -229,6 +229,7 @@
         Thread.stop
       end
     }
+    sleep 1 #to be sure that server is running
     @socket = TCPSocket.new('127.0.0.1',$port)
 
     ok = false  
Index: test/xml/ticket_110_utf16.xml
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: test/xml/ticket_110_utf16.xml
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Index: src/rexml/parsers/xpathparser.rb
===================================================================
--- src/rexml/parsers/xpathparser.rb	(revision 1287)
+++ src/rexml/parsers/xpathparser.rb	(working copy)
@@ -332,12 +332,12 @@
           predicates << expr[1..-2] if expr
         end
         #puts "PREDICATES = #{predicates.inspect}"
-        predicates.each{ |expr| 
-          #puts "ORING #{expr}"
+        predicates.each{ |pred| 
+          #puts "ORING #{pred}"
           preds = []
           parsed << :predicate
           parsed << preds
-          OrExpr(expr, preds) 
+          OrExpr(pred, preds) 
         }
         #puts "PREDICATES = #{predicates.inspect}"
         path
Index: src/rexml/parsers/baseparser.rb
===================================================================
--- src/rexml/parsers/baseparser.rb	(revision 1287)
+++ src/rexml/parsers/baseparser.rb	(working copy)
@@ -242,6 +242,11 @@
             @document_status = :after_doctype
             @source.read if @source.buffer.size<2
             md = @source.match(/\s*/um, true)
+            if @source.encoding == "UTF-8"
+              if @source.buffer.respond_to? :force_encoding
+                @source.buffer.force_encoding(Encoding::UTF_8)
+              end
+            end
           end
         end
         if @document_status == :in_doctype
Index: src/rexml/parsers/sax2parser.rb
===================================================================
--- src/rexml/parsers/sax2parser.rb	(revision 1287)
+++ src/rexml/parsers/sax2parser.rb	(working copy)
@@ -149,17 +149,26 @@
 						procs = get_procs( :end_prefix_mapping, event[1] )
 						listeners = get_listeners( :end_prefix_mapping, event[1] )
 						if procs or listeners
-							namespace_mapping.each do |prefix, uri|
+							namespace_mapping.each do |ns_prefix, ns_uri|
 								# notify observers of namespaces
-								procs.each { |ob| ob.call( prefix ) } if procs
-								listeners.each { |ob| ob.end_prefix_mapping(prefix) } if listeners
+								procs.each { |ob| ob.call( ns_prefix ) } if procs
+								listeners.each { |ob| ob.end_prefix_mapping(ns_prefix) } if listeners
 							end
 						end
 					when :text
             #normalized = @parser.normalize( event[1] )
             #handle( :characters, normalized )
             copy = event[1].clone
-            @entities.each { |key, value| copy = copy.gsub("&#{key};", value) }
+
+            esub = proc { |match| 
+              if @entities.has_key?($1)
+                @entities[$1].gsub(Text::REFERENCE, &esub)
+              else
+                match
+              end
+            }
+
+            copy.gsub!( Text::REFERENCE, &esub )
             copy.gsub!( Text::NUMERICENTITY ) {|m|
               m=$1
               m = "0#{m}" if m[0] == ?x
Index: src/rexml/parsers/treeparser.rb
===================================================================
--- src/rexml/parsers/treeparser.rb	(revision 1287)
+++ src/rexml/parsers/treeparser.rb	(working copy)
@@ -30,7 +30,10 @@
               return
             when :start_element
               tag_stack.push(event[1])
-              el = @build_context = @build_context.add_element( event[1], event[2] )
+              el = @build_context = @build_context.add_element( event[1] )
+              event[2].each do |key, value|
+                el.attributes[key]=Attribute.new(key,value,self)
+              end
             when :end_element
               tag_stack.pop
               @build_context = @build_context.parent
Index: src/rexml/validation/validation.rb
===================================================================
--- src/rexml/validation/validation.rb	(revision 1287)
+++ src/rexml/validation/validation.rb	(working copy)
@@ -33,8 +33,8 @@
             sattr = [:start_attribute, nil]
             eattr = [:end_attribute]
             text = [:text, nil]
-            k,v = event[2].find { |k,v| 
-              sattr[1] = k
+            k,v = event[2].find { |key,value| 
+              sattr[1] = key
               #puts "Looking for #{sattr.inspect}"
               m = @current.next( sattr )
               #puts "Got #{m.inspect}"
@@ -47,7 +47,7 @@
                   @current = m
                 else
                   #puts "Didn't get end"
-                  text[1] = v
+                  text[1] = value
                   #puts "Looking for #{text.inspect}"
                   m = m.next( text )
                   #puts "Got #{m.inspect}"
Index: src/rexml/element.rb
===================================================================
--- src/rexml/element.rb	(revision 1287)
+++ src/rexml/element.rb	(working copy)
@@ -296,7 +296,7 @@
       raise "First argument must be either an element name, or an Element object" if element.nil?
       el = @elements.add(element)
       attrs.each do |key, value|
-        el.attributes[key]=Attribute.new(key,value,self)
+        el.attributes[key]=value
       end	if attrs.kind_of? Hash
       el
     end
@@ -552,7 +552,11 @@
 
     def attribute( name, namespace=nil )
       prefix = nil
-      prefix = namespaces.index(namespace) if namespace
+      if namespaces.respond_to? :key
+        prefix = namespaces.key(namespace) if namespace
+      else
+        prefix = namespaces.index(namespace) if namespace
+      end
       prefix = nil if prefix == 'xmlns'
       attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
     end
@@ -704,7 +708,6 @@
     # A private helper method
     def each_with_something( test, max=0, name=nil )
       num = 0
-      child=nil
       @elements.each( name ){ |child|
         yield child if test.call(child) and num += 1
         return if max>0 and num == max
@@ -754,7 +757,6 @@
         raise "index (#{index}) must be >= 1" if index < 1
         name = literalize(name) if name
         num = 0
-        child = nil
         @element.find { |child|
           child.kind_of? Element and
           (name.nil? ? true : child.has_name?( name )) and 
@@ -1217,7 +1219,8 @@
     def get_attribute_ns(namespace, name)
       each_attribute() { |attribute|
         if name == attribute.name &&
-          namespace == attribute.namespace()
+          namespace == attribute.namespace() &&
+          ( !namespace.empty? || !attribute.fully_expanded_name.index(':') )
           return attribute
         end
       }
Index: src/rexml/source.rb
===================================================================
--- src/rexml/source.rb	(revision 1287)
+++ src/rexml/source.rb	(working copy)
@@ -58,6 +58,9 @@
         @to_utf = true
       else
         @to_utf = false
+        if @buffer.respond_to? :force_encoding
+          @buffer.force_encoding Encoding::UTF_8
+        end
       end
     end
 
@@ -146,13 +149,13 @@
       str = @source.read( 2 )
       if encoding
         self.encoding = encoding
-      elsif 0xfe == str[0] && 0xff == str[1]
+      elsif str[0,2] == "\xfe\xff"
         @line_break = "\000>"
-      elsif 0xff == str[0] && 0xfe == str[1]
+      elsif str[0,2] == "\xff\xfe"
         @line_break = ">\000"
-      elsif 0xef == str[0] && 0xbb == str[1]
+      elsif str[0,2] == "\xef\xbb"
         str += @source.read(1)
-        str = '' if (0xbf == str[2])
+        str = '' if (str[2,1] == "\xBF")
         @line_break = ">"
       else
         @line_break = ">"
@@ -192,6 +195,9 @@
         str = @source.readline(@line_break)
         str = decode(str) if @to_utf and str 
         @buffer << str
+        if not @to_utf and @buffer.respond_to? :force_encoding
+          @buffer.force_encoding Encoding::UTF_8
+        end
       rescue Exception, NameError
         @source = nil
       end
Index: src/rexml/doctype.rb
===================================================================
--- src/rexml/doctype.rb	(revision 1287)
+++ src/rexml/doctype.rb	(working copy)
@@ -117,7 +117,6 @@
       unless @children.empty?
         next_indent = indent + 1
         output << ' ['
-        child = nil    # speed
         @children.each { |child|
           output << "\n"
           f.write( child, output )
Index: src/rexml/functions.rb
===================================================================
--- src/rexml/functions.rb	(revision 1287)
+++ src/rexml/functions.rb	(working copy)
@@ -256,9 +256,15 @@
         end
       }
 
-      string(string).unpack('U*').collect { |c|
-        if map.has_key? c then map[c] else c end
-      }.compact.pack('U*')
+      if ''.respond_to? :chars
+        string(string).chars.collect { |c|
+          if map.has_key? c then map[c] else c end
+        }.compact.join
+      else
+        string(string).unpack('U*').collect { |c|
+          if map.has_key? c then map[c] else c end
+        }.compact.pack('U*')
+      end
     end
 
     # UNTESTED
Index: src/rexml/entity.rb
===================================================================
--- src/rexml/entity.rb	(revision 1287)
+++ src/rexml/entity.rb	(working copy)
@@ -139,7 +139,7 @@
 				if @parent
 					matches.each do |entity_reference|
 						entity_value = @parent.entity( entity_reference[0] )
-						rv.gsub!( /%#{entity_reference};/um, entity_value )
+						rv.gsub!( /%#{entity_reference.join};/um, entity_value )
 					end
 				end
 				return rv
Index: src/rexml/syncenumerator.rb
===================================================================
--- src/rexml/syncenumerator.rb	(revision 1287)
+++ src/rexml/syncenumerator.rb	(working copy)
@@ -6,8 +6,7 @@
     # Enumerable objects.
     def initialize(*enums)
       @gens = enums
-      @biggest = @gens[0]
-      @gens.each {|x| @biggest = x if x.size > @biggest.size }
+      @length = @gens.collect {|x| x.size }.max
     end
 
     # Returns the number of enumerated Enumerable objects, i.e. the size
@@ -24,8 +23,8 @@
 
     # Enumerates rows of the Enumerable objects.
     def each
-      @biggest.zip( *@gens ) {|a|
-        yield(*a[1..-1])
+      @length.times {|i|
+        yield @gens.collect {|x| x[i]}
       }
       self
     end
Index: src/rexml/text.rb
===================================================================
--- src/rexml/text.rb	(revision 1287)
+++ src/rexml/text.rb	(working copy)
@@ -308,37 +308,24 @@
 
     # Unescapes all possible entities
     def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil )
-      rv = string.clone
-      rv.gsub!( /\r\n?/, "\n" )
-      matches = rv.scan( REFERENCE )
-      return rv if matches.size == 0
-      rv.gsub!( NUMERICENTITY ) {|m|
-        m=$1
-        m = "0#{m}" if m[0] == ?x
-        [Integer(m)].pack('U*')
-      }
-      matches.collect!{|x|x[0]}.compact!
-      if matches.size > 0
-        if doctype
-          matches.each do |entity_reference|
-            unless filter and filter.include?(entity_reference)
-              entity_value = doctype.entity( entity_reference )
-              re = /&#{entity_reference};/
-              rv.gsub!( re, entity_value ) if entity_value
-            end
+      string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) { |ref|
+        if ref[1] == ?#
+          if ref[2] == ?x
+            [ref[3...-1].to_i(16)].pack('U*')
+          else
+            [ref[2...-1].to_i].pack('U*')
           end
+        elsif ref == '&amp;'
+          '&'
+        elsif filter and filter.include?( ref[1...-1] )
+          ref
+        elsif doctype
+          doctype.entity( ref[1...-1] ) or ref
         else
-          matches.each do |entity_reference|
-            unless filter and filter.include?(entity_reference)
-              entity_value = DocType::DEFAULT_ENTITIES[ entity_reference ]
-              re = /&#{entity_reference};/
-              rv.gsub!( re, entity_value.value ) if entity_value
-            end
-          end
+          entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
+          entity_value ? entity_value.value : ref
         end
-        rv.gsub!( /&amp;/, '&' )
-      end
-      rv
+      }
     end
   end
 end
Index: src/rexml/formatters/pretty.rb
===================================================================
--- src/rexml/formatters/pretty.rb	(revision 1287)
+++ src/rexml/formatters/pretty.rb	(working copy)
@@ -31,6 +31,7 @@
         @level = 0
         @ie_hack = ie_hack
         @width = 80
+        @compact = false
       end
 
       protected
Index: src/rexml/encoding.rb
===================================================================
--- src/rexml/encoding.rb	(revision 1287)
+++ src/rexml/encoding.rb	(working copy)
@@ -56,14 +56,14 @@
 
     def check_encoding str
       # We have to recognize UTF-16, LSB UTF-16, and UTF-8
-      if str[0] == 0xfe && str[1] == 0xff
+      if str[0,2] == "\xfe\xff"
         str[0,2] = ""
         return UTF_16
-      elsif str[0] == 0xff && str[1] == 0xfe
+      elsif str[0,2] == "\xff\xfe"
         str[0,2] = ""
         return UNILE
       end
-      str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/um
+      str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/m
       return $3.upcase if $3
       return UTF_8
     end
Index: src/rexml/xpath_parser.rb
===================================================================
--- src/rexml/xpath_parser.rb	(revision 1287)
+++ src/rexml/xpath_parser.rb	(working copy)
@@ -222,7 +222,7 @@
         when :child
           new_nodeset = []
           nt = nil
-          for node in nodeset
+          nodeset.each do |node|
             nt = node.node_type
             new_nodeset += node.children if nt == :element or nt == :document
           end
@@ -266,7 +266,7 @@
 
         when :ancestor
           new_nodeset = []
-          for node in nodeset
+          nodeset.each do |node|
             while node.parent
               node = node.parent
               new_nodeset << node unless new_nodeset.include? node
@@ -277,7 +277,7 @@
 
         when :ancestor_or_self
           new_nodeset = []
-          for node in nodeset
+          nodeset.each do |node|
             if node.node_type == :element
               new_nodeset << node
               while ( node.parent )
@@ -341,7 +341,7 @@
         when :descendant
           results = []
           nt = nil
-          for node in nodeset
+          nodeset.each do |node|
             nt = node.node_type
             results += expr( path_stack.dclone.unshift( :descendant_or_self ),
               node.children ) if nt == :element or nt == :document
@@ -376,7 +376,7 @@
 
         when :preceding
           new_nodeset = []
-          for node in nodeset
+          nodeset.each do |node|
             new_nodeset += preceding( node )
           end
           #puts "NEW NODESET => #{new_nodeset.inspect}"
@@ -385,7 +385,7 @@
 
         when :following
           new_nodeset = []
-          for node in nodeset
+          nodeset.each do |node|
             new_nodeset += following( node )
           end
           nodeset = new_nodeset
@@ -395,7 +395,7 @@
           #puts "In :namespace"
           new_nodeset = []
           prefix = path_stack.shift
-          for node in nodeset
+          nodeset.each do |node|
             if (node.node_type == :element or node.node_type == :attribute)
               if @namespaces
                 namespaces = @namespaces
