* lib/rexml: Merge fixes since 1.8.6 made solely on the ruby_1_8_6

branch.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@16067 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
knu 2008-04-18 07:07:11 +00:00
parent 40e7794993
commit 2f1fa7e402
28 changed files with 1785 additions and 1373 deletions

View file

@ -1,3 +1,8 @@
Fri Apr 18 16:01:37 2008 Akinori MUSHA <knu@iDaemons.org>
* lib/rexml: Merge fixes since 1.8.6 made solely on the ruby_1_8_6
branch.
Fri Apr 18 07:56:18 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> Fri Apr 18 07:56:18 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk.rb, ext/tk/lib/tk/scrollbar.rb, ext/tk/lib/tk/scale.rb: * ext/tk/lib/tk.rb, ext/tk/lib/tk/scrollbar.rb, ext/tk/lib/tk/scale.rb:

View file

@ -18,25 +18,41 @@ module REXML
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
# Constructor. # Constructor.
# FIXME: The parser doesn't catch illegal characters in attributes
#
# first::
# Either: an Attribute, which this new attribute will become a
# clone of; or a String, which is the name of this attribute
# second::
# If +first+ is an Attribute, then this may be an Element, or nil.
# If nil, then the Element parent of this attribute is the parent
# of the +first+ Attribute. If the first argument is a String,
# then this must also be a String, and is the content of the attribute.
# If this is the content, it must be fully normalized (contain no
# illegal characters).
# parent::
# Ignored unless +first+ is a String; otherwise, may be the Element
# parent of this attribute, or nil.
#
# #
# Attribute.new( attribute_to_clone ) # Attribute.new( attribute_to_clone )
# Attribute.new( source ) # Attribute.new( attribute_to_clone, parent_element )
# Attribute.new( "attr", "attr_value" ) # Attribute.new( "attr", "attr_value" )
# Attribute.new( "attr", "attr_value", parent_element ) # Attribute.new( "attr", "attr_value", parent_element )
def initialize( first, second=nil, parent=nil ) def initialize( first, second=nil, parent=nil )
@normalized = @unnormalized = @element = nil @normalized = @unnormalized = @element = nil
if first.kind_of? Attribute if first.kind_of? Attribute
self.name = first.expanded_name self.name = first.expanded_name
@value = first.value @unnormalized = first.value
if second.kind_of? Element if second.kind_of? Element
@element = second @element = second
else else
@element = first.element @element = first.element
end end
elsif first.kind_of? String elsif first.kind_of? String
@element = parent if parent.kind_of? Element @element = parent
self.name = first self.name = first
@value = second.to_s @normalized = second.to_s
else else
raise "illegal argument #{first.class.name} to Attribute constructor" raise "illegal argument #{first.class.name} to Attribute constructor"
end end
@ -72,7 +88,7 @@ module REXML
# Returns true if other is an Attribute and has the same name and value, # Returns true if other is an Attribute and has the same name and value,
# false otherwise. # false otherwise.
def ==( other ) def ==( other )
other.kind_of?(Attribute) and other.name==name and other.value==@value other.kind_of?(Attribute) and other.name==name and other.value==value
end end
# Creates (and returns) a hash from both the name and value # Creates (and returns) a hash from both the name and value
@ -87,8 +103,12 @@ module REXML
# b = Attribute.new( "ns:x", "y" ) # b = Attribute.new( "ns:x", "y" )
# b.to_string # -> "ns:x='y'" # b.to_string # -> "ns:x='y'"
def to_string def to_string
if @element and @element.context and @element.context[:attribute_quote] == :quote
%Q^#@expanded_name="#{to_s().gsub(/"/, '&quote;')}"^
else
"#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'" "#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
end end
end
# Returns the attribute value, with entities replaced # Returns the attribute value, with entities replaced
def to_s def to_s
@ -100,8 +120,9 @@ module REXML
doctype = doc.doctype if doc doctype = doc.doctype if doc
end end
@normalized = Text::normalize( @unnormalized, doctype )
@unnormalized = nil @unnormalized = nil
@normalized = Text::normalize( @value, doctype ) @normalized
end end
# Returns the UNNORMALIZED value of this attribute. That is, entities # Returns the UNNORMALIZED value of this attribute. That is, entities
@ -113,8 +134,9 @@ module REXML
doc = @element.document doc = @element.document
doctype = doc.doctype if doc doctype = doc.doctype if doc
end end
@unnormalized = Text::unnormalize( @normalized, doctype )
@normalized = nil @normalized = nil
@unnormalized = Text::unnormalize( @value, doctype ) @unnormalized
end end
# Returns a copy of this attribute # Returns a copy of this attribute

View file

@ -39,31 +39,26 @@ module REXML
@string @string
end end
# == DEPRECATED
# See the rexml/formatters package
#
# Generates XML output of this object # Generates XML output of this object
# #
# output:: # output::
# Where to write the string. Defaults to $stdout # Where to write the string. Defaults to $stdout
# indent:: # indent::
# An integer. If -1, no indenting will be used; otherwise, the # The amount to indent this node by
# indentation will be this number of spaces, and children will be
# indented an additional amount. Defaults to -1.
# transitive:: # transitive::
# If transitive is true and indent is >= 0, then the output will be # Ignored
# pretty-printed in such a way that the added whitespace does not affect
# the absolute *value* of the document -- that is, it leaves the value
# and number of Text nodes in the document unchanged.
# ie_hack:: # ie_hack::
# Internet Explorer is the worst piece of crap to have ever been # Ignored
# written, with the possible exception of Windows itself. Since IE is
# unable to parse proper XML, we have to provide a hack to generate XML
# that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags.
# #
# _Examples_ # _Examples_
# c = CData.new( " Some text " ) # c = CData.new( " Some text " )
# c.write( $stdout ) #-> <![CDATA[ Some text ]]> # c.write( $stdout ) #-> <![CDATA[ Some text ]]>
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
#indent( output, indent ) unless transitive Kernel.warn( "#{self.class.name}.write is deprecated" )
indent( output, indent )
output << START output << START
output << @string output << @string
output << STOP output << STOP

View file

@ -34,6 +34,9 @@ module REXML
Comment.new self Comment.new self
end end
# == DEPRECATED
# See REXML::Formatters
#
# output:: # output::
# Where to write the string # Where to write the string
# indent:: # indent::
@ -45,6 +48,7 @@ module REXML
# ie_hack:: # ie_hack::
# Needed for conformity to the child API, but not used by this class. # Needed for conformity to the child API, but not used by this class.
def write( output, indent=-1, transitive=false, ie_hack=false ) def write( output, indent=-1, transitive=false, ie_hack=false )
Kernel.warn("Comment.write is deprecated. See REXML::Formatters")
indent( output, indent ) indent( output, indent )
output << START output << START
output << @string output << @string

View file

@ -98,38 +98,30 @@ module REXML
# output:: # output::
# Where to write the string # Where to write the string
# indent:: # indent::
# An integer. If -1, no indenting will be used; otherwise, the # An integer. If -1, no indentation will be used; otherwise, the
# indentation will be this number of spaces, and children will be # indentation will be this number of spaces, and children will be
# indented an additional amount. # indented an additional amount.
# transitive:: # transitive::
# If transitive is true and indent is >= 0, then the output will be # Ignored
# pretty-printed in such a way that the added whitespace does not affect
# the absolute *value* of the document -- that is, it leaves the value
# and number of Text nodes in the document unchanged.
# ie_hack:: # ie_hack::
# Internet Explorer is the worst piece of crap to have ever been # Ignored
# written, with the possible exception of Windows itself. Since IE is
# unable to parse proper XML, we have to provide a hack to generate XML
# that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags.
#
def write( output, indent=0, transitive=false, ie_hack=false ) def write( output, indent=0, transitive=false, ie_hack=false )
f = REXML::Formatters::Default.new
indent( output, indent ) indent( output, indent )
output << START output << START
output << ' ' output << ' '
output << @name output << @name
output << " #@external_id" if @external_id output << " #@external_id" if @external_id
output << " #@long_name" if @long_name output << " #{@long_name.inspect}" if @long_name
output << " #@uri" if @uri output << " #{@uri.inspect}" if @uri
unless @children.empty? unless @children.empty?
next_indent = indent + 1 next_indent = indent + 1
output << ' [' output << ' ['
child = nil # speed child = nil # speed
@children.each { |child| @children.each { |child|
output << "\n" output << "\n"
child.write( output, next_indent ) f.write( child, output )
} }
#output << ' '*next_indent
output << "\n]" output << "\n]"
end end
output << STOP output << STOP
@ -219,8 +211,10 @@ module REXML
@string+'>' @string+'>'
end end
# == DEPRECATED
# See REXML::Formatters
#
def write( output, indent ) def write( output, indent )
output << (' '*indent) if indent > 0
output << to_s output << to_s
end end
end end
@ -264,7 +258,6 @@ module REXML
end end
def write( output, indent=-1 ) def write( output, indent=-1 )
output << (' '*indent) if indent > 0
output << to_s output << to_s
end end

View file

@ -31,9 +31,6 @@ module REXML
# to be sources of valid XML documents. # to be sources of valid XML documents.
# @param context if supplied, contains the context of the document; # @param context if supplied, contains the context of the document;
# this should be a Hash. # this should be a Hash.
# NOTE that I'm not sure what the context is for; I cloned it out of
# the Electric XML API (in which it also seems to do nothing), and it
# is now legacy. It may do something, someday... it may disappear.
def initialize( source = nil, context = {} ) def initialize( source = nil, context = {} )
super() super()
@context = context @context = context
@ -69,6 +66,7 @@ module REXML
def add( child ) def add( child )
if child.kind_of? XMLDecl if child.kind_of? XMLDecl
@children.unshift child @children.unshift child
child.parent = self
elsif child.kind_of? DocType elsif child.kind_of? DocType
# Find first Element or DocType node and insert the decl right # Find first Element or DocType node and insert the decl right
# before it. If there is no such node, just insert the child at the # before it. If there is no such node, just insert the child at the
@ -145,21 +143,32 @@ module REXML
# Write the XML tree out, optionally with indent. This writes out the # Write the XML tree out, optionally with indent. This writes out the
# entire XML document, including XML declarations, doctype declarations, # entire XML document, including XML declarations, doctype declarations,
# and processing instructions (if any are given). # and processing instructions (if any are given).
#
# A controversial point is whether Document should always write the XML # A controversial point is whether Document should always write the XML
# declaration (<?xml version='1.0'?>) whether or not one is given by the # declaration (<?xml version='1.0'?>) whether or not one is given by the
# user (or source document). REXML does not write one if one was not # user (or source document). REXML does not write one if one was not
# specified, because it adds unneccessary bandwidth to applications such # specified, because it adds unneccessary bandwidth to applications such
# as XML-RPC. # as XML-RPC.
# #
# See also the classes in the rexml/formatters package for the proper way
# to change the default formatting of XML output
#
# _Examples_
# Document.new("<a><b/></a>").serialize
#
# output_string = ""
# tr = Transitive.new( output_string )
# Document.new("<a><b/></a>").serialize( tr )
# #
# output:: # output::
# output an object which supports '<< string'; this is where the # output an object which supports '<< string'; this is where the
# document will be written. # document will be written.
# indent:: # indent::
# An integer. If -1, no indenting will be used; otherwise, the # An integer. If -1, no indenting will be used; otherwise, the
# indentation will be this number of spaces, and children will be # indentation will be twice this number of spaces, and children will be
# indented an additional amount. Defaults to -1 # indented an additional amount. For a value of 3, every item will be
# transitive:: # indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
# trans::
# If transitive is true and indent is >= 0, then the output will be # If transitive is true and indent is >= 0, then the output will be
# pretty-printed in such a way that the added whitespace does not affect # pretty-printed in such a way that the added whitespace does not affect
# the absolute *value* of the document -- that is, it leaves the value # the absolute *value* of the document -- that is, it leaves the value
@ -170,14 +179,20 @@ module REXML
# unable to parse proper XML, we have to provide a hack to generate XML # unable to parse proper XML, we have to provide a hack to generate XML
# that IE's limited abilities can handle. This hack inserts a space # that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags. Defaults to false # before the /> on empty tags. Defaults to false
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) def write( output=$stdout, indent=-1, trans=false, ie_hack=false )
output = Output.new( output, xml_decl.encoding ) if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
@children.each { |node| output = Output.new( output, xml_decl.encoding )
indent( output, indent ) if node.node_type == :element
if node.write( output, indent, transitive, ie_hack )
output << "\n" unless indent<0 or node == @children[-1]
end end
} formatter = if indent > -1
if trans
REXML::Formatters::Transitive.new( indent, ie_hack )
else
REXML::Formatters::Pretty.new( indent, ie_hack )
end
else
REXML::Formatters::Default.new( ie_hack )
end
formatter.write( self, output )
end end

View file

@ -295,14 +295,9 @@ module REXML
def add_element element, attrs=nil def add_element element, attrs=nil
raise "First argument must be either an element name, or an Element object" if element.nil? raise "First argument must be either an element name, or an Element object" if element.nil?
el = @elements.add(element) el = @elements.add(element)
if attrs.kind_of? Hash
attrs.each do |key, value| attrs.each do |key, value|
el.attributes[key]=value if key =~ /^xmlns:/ el.attributes[key]=Attribute.new(key,value,self)
end end if attrs.kind_of? Hash
attrs.each do |key, value|
el.attributes[key]=value if key !~ /^xmlns:/
end
end
el el
end end
@ -558,6 +553,7 @@ module REXML
def attribute( name, namespace=nil ) def attribute( name, namespace=nil )
prefix = nil prefix = nil
prefix = namespaces.index(namespace) if namespace prefix = namespaces.index(namespace) if namespace
prefix = nil if prefix == 'xmlns'
attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" ) attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
end end
@ -577,7 +573,8 @@ module REXML
# value:: # value::
# Required if +key+ is a String, and ignored if the first argument is # Required if +key+ is a String, and ignored if the first argument is
# an Attribute. This is a String, and is used as the value # an Attribute. This is a String, and is used as the value
# of the new Attribute. # of the new Attribute. This should be the unnormalized value of the
# attribute (without entities).
# Returns:: the Attribute added # Returns:: the Attribute added
# e = Element.new 'e' # e = Element.new 'e'
# e.add_attribute( 'a', 'b' ) #-> <e a='b'/> # e.add_attribute( 'a', 'b' ) #-> <e a='b'/>
@ -649,6 +646,9 @@ module REXML
find_all { |child| child.kind_of? Text }.freeze find_all { |child| child.kind_of? Text }.freeze
end end
# == DEPRECATED
# See REXML::Formatters
#
# Writes out this element, and recursively, all children. # Writes out this element, and recursively, all children.
# output:: # output::
# output an object which supports '<< string'; this is where the # output an object which supports '<< string'; this is where the
@ -672,37 +672,17 @@ module REXML
# doc.write( out ) #-> doc is written to the string 'out' # doc.write( out ) #-> doc is written to the string 'out'
# doc.write( $stdout ) #-> doc written to the console # doc.write( $stdout ) #-> doc written to the console
def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false) def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false)
#print "ID:#{indent}" Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters")
writer << "<#@expanded_name" formatter = if indent > -1
if transitive
@attributes.each_attribute do |attr| REXML::Formatters::Transitive.new( indent, ie_hack )
writer << " "
attr.write( writer, indent )
end unless @attributes.empty?
if @children.empty?
if transitive and indent>-1
writer << "\n"
indent( writer, indent )
elsif ie_hack
writer << " "
end
writer << "/"
else else
if transitive and indent>-1 and !@children[0].kind_of? Text REXML::Formatters::Pretty.new( indent, ie_hack )
writer << "\n"
indent writer, indent+1
end end
writer << ">" else
write_children( writer, indent, transitive, ie_hack ) REXML::Formatters::Default.new( ie_hack )
writer << "</#{expanded_name}"
end end
if transitive and indent>-1 and !@children.empty? formatter.write( self, output )
writer << "\n"
indent -= 1 if next_sibling.nil?
indent(writer, indent)
end
writer << ">"
end end
@ -730,29 +710,6 @@ module REXML
return if max>0 and num == max return if max>0 and num == max
} }
end end
# A private helper method
def write_children( writer, indent, transitive, ie_hack )
cr = (indent < 0) ? '' : "\n"
if indent == -1
each { |child| child.write( writer, indent, transitive, ie_hack ) }
else
next_indent = indent+1
last_child=nil
each { |child|
unless child.kind_of? Text or last_child.kind_of? Text or transitive
writer << cr
indent(writer, next_indent)
end
child.write( writer, next_indent, transitive, ie_hack )
last_child = child
}
unless last_child.kind_of? Text or transitive
writer << cr
indent( writer, indent )
end
end
end
end end
######################################################################## ########################################################################
@ -898,15 +855,15 @@ module REXML
# Source (see Element.initialize). If not supplied or nil, a # Source (see Element.initialize). If not supplied or nil, a
# new, default Element will be constructed # new, default Element will be constructed
# Returns:: the added Element # Returns:: the added Element
# a = Element.new 'a' # a = Element.new('a')
# a.elements.add Element.new 'b' #-> <a><b/></a> # a.elements.add(Element.new('b')) #-> <a><b/></a>
# a.elements.add 'c' #-> <a><b/><c/></a> # a.elements.add('c') #-> <a><b/><c/></a>
def add element=nil def add element=nil
rv = nil rv = nil
if element.nil? if element.nil?
Element.new "", self, @element.context Element.new("", self, @element.context)
elsif not element.kind_of?(Element) elsif not element.kind_of?(Element)
Element.new element, self, @element.context Element.new(element, self, @element.context)
else else
@element << element @element << element
element.context = @element.context element.context = @element.context
@ -1006,10 +963,11 @@ module REXML
# name:: an XPath attribute name. Namespaces are relevant here. # name:: an XPath attribute name. Namespaces are relevant here.
# Returns:: # Returns::
# the String value of the matching attribute, or +nil+ if no # the String value of the matching attribute, or +nil+ if no
# matching attribute was found. # matching attribute was found. This is the unnormalized value
# (with entities expanded).
# #
# doc = Document.new "<a foo:att='1' bar:att='2' att='3'/>" # doc = Document.new "<a foo:att='1' bar:att='2' att='&lt;'/>"
# doc.root.attributes['att'] #-> '3' # doc.root.attributes['att'] #-> '<'
# doc.root.attributes['bar:att'] #-> '2' # doc.root.attributes['bar:att'] #-> '2'
def [](name) def [](name)
attr = get_attribute(name) attr = get_attribute(name)
@ -1119,7 +1077,15 @@ module REXML
delete attr delete attr
return return
end end
value = Attribute.new(name, value) unless value.kind_of? Attribute element_document = @element.document
unless value.kind_of? Attribute
if @element.document and @element.document.doctype
value = Text::normalize( value, @element.document.doctype )
else
value = Text::normalize( value, nil )
end
value = Attribute.new(name, value)
end
value.element = @element value.element = @element
old_attr = fetch(value.name, nil) old_attr = fetch(value.name, nil)
if old_attr.nil? if old_attr.nil?

View file

@ -56,10 +56,15 @@ module REXML
def check_encoding str def check_encoding str
# We have to recognize UTF-16, LSB UTF-16, and UTF-8 # We have to recognize UTF-16, LSB UTF-16, and UTF-8
return UTF_16 if /\A\xfe\xff/n =~ str if str[0] == 0xfe && str[1] == 0xff
return UNILE if /\A\xff\xfe/n =~ str str[0,2] = ""
str =~ /^\s*<?xml\s*version\s*=\s*(['"]).*?\2\s*encoding\s*=\s*(["'])(.*?)\2/um return UTF_16
return $1.upcase if $1 elsif str[0] == 0xff && str[1] == 0xfe
str[0,2] = ""
return UNILE
end
str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/um
return $3.upcase if $3
return UTF_8 return UTF_8
end end
end end

View file

@ -3,9 +3,15 @@
# #
module REXML module REXML
module Encoding module Encoding
@@__REXML_encoding_methods = %q~ register( "CP-1252" ) do |o|
class << o
alias encode encode_cp1252
alias decode decode_cp1252
end
end
# Convert from UTF-8 # Convert from UTF-8
def encode content def encode_cp1252(content)
array_utf8 = content.unpack('U*') array_utf8 = content.unpack('U*')
array_enc = [] array_enc = []
array_utf8.each do |num| array_utf8.each do |num|
@ -54,7 +60,7 @@ module REXML
end end
# Convert to UTF-8 # Convert to UTF-8
def decode(str) def decode_cp1252(str)
array_latin9 = str.unpack('C*') array_latin9 = str.unpack('C*')
array_enc = [] array_enc = []
array_latin9.each do |num| array_latin9.each do |num|
@ -93,6 +99,5 @@ module REXML
end end
array_enc.pack('U*') array_enc.pack('U*')
end end
~
end end
end end

View file

@ -3,9 +3,13 @@
# #
module REXML module REXML
module Encoding module Encoding
@@__REXML_encoding_methods = %q~ register("ISO-8859-15") do |o|
alias encode to_iso_8859_15
alias decode from_iso_8859_15
end
# Convert from UTF-8 # Convert from UTF-8
def to_iso_8859_15 content def to_iso_8859_15(content)
array_utf8 = content.unpack('U*') array_utf8 = content.unpack('U*')
array_enc = [] array_enc = []
array_utf8.each do |num| array_utf8.each do |num|
@ -64,6 +68,5 @@ module REXML
end end
array_enc.pack('U*') array_enc.pack('U*')
end end
~
end end
end end

View file

@ -16,7 +16,7 @@ module REXML
end end
def decode_utf16(str) def decode_utf16(str)
str = str[2..-1] if /^\376\377/ =~ str str = str[2..-1] if /^\376\377/n =~ str
array_enc=str.unpack('C*') array_enc=str.unpack('C*')
array_utf8 = [] array_utf8 = []
0.step(array_enc.size-1, 2){|i| 0.step(array_enc.size-1, 2){|i|

View file

@ -89,6 +89,12 @@ module REXML
# Write out a fully formed, correct entity definition (assuming the Entity # Write out a fully formed, correct entity definition (assuming the Entity
# object itself is valid.) # object itself is valid.)
#
# out::
# An object implementing <TT>&lt;&lt;<TT> to which the entity will be
# output
# indent::
# *DEPRECATED* and ignored
def write out, indent=-1 def write out, indent=-1
out << '<!ENTITY ' out << '<!ENTITY '
out << '% ' if @reference out << '% ' if @reference

View file

@ -0,0 +1,109 @@
module REXML
module Formatters
class Default
# Prints out the XML document with no formatting -- except if id_hack is
# set.
#
# ie_hack::
# If set to true, then inserts whitespace before the close of an empty
# tag, so that IE's bad XML parser doesn't choke.
def initialize( ie_hack=false )
@ie_hack = ie_hack
end
# Writes the node to some output.
#
# node::
# The node to write
# output::
# A class implementing <TT>&lt;&lt;</TT>. Pass in an Output object to
# change the output encoding.
def write( node, output )
case node
when Document
if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
output = Output.new( output, node.xml_decl.encoding )
end
write_document( node, output )
when Element
write_element( node, output )
when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity,
Attribute, AttlistDecl
node.write( output,-1 )
when Instruction
write_instruction( node, output )
when DocType, XMLDecl
node.write( output )
when Comment
write_comment( node, output )
when CData
write_cdata( node, output )
when Text
write_text( node, output )
else
raise Exception.new("XML FORMATTING ERROR")
end
end
protected
def write_document( node, output )
node.children.each { |child| write( child, output ) }
end
def write_element( node, output )
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
output << " " if @ie_hack
output << "/"
else
output << ">"
node.children.each { |child|
write( child, output )
}
output << "</#{node.expanded_name}"
end
output << ">"
end
def write_text( node, output )
output << node.to_s()
end
def write_comment( node, output )
output << Comment::START
output << node.to_s
output << Comment::STOP
end
def write_cdata( node, output )
output << CData::START
output << node.to_s
output << CData::STOP
end
def write_instruction( node, output )
output << Instruction::START.sub(/\\/u, '')
output << node.target
output << ' '
output << node.content
output << Instruction::STOP.sub(/\\/u, '')
end
end
end
end

View file

@ -0,0 +1,137 @@
require 'rexml/formatters/default'
module REXML
module Formatters
# Pretty-prints an XML document. This destroys whitespace in text nodes
# and will insert carriage returns and indentations.
#
# TODO: Add an option to print attributes on new lines
class Pretty < Default
# If compact is set to true, then the formatter will attempt to use as
# little space as possible
attr_accessor :compact
# The width of a page. Used for formatting text
attr_accessor :width
# Create a new pretty printer.
#
# output::
# An object implementing '<<(String)', to which the output will be written.
# indentation::
# An integer greater than 0. The indentation of each level will be
# this number of spaces. If this is < 1, the behavior of this object
# is undefined. Defaults to 2.
# ie_hack::
# If true, the printer will insert whitespace before closing empty
# tags, thereby allowing Internet Explorer's feeble XML parser to
# function. Defaults to false.
def initialize( indentation=2, ie_hack=false )
@indentation = indentation
@level = 0
@ie_hack = ie_hack
@width = 80
end
protected
def write_element(node, output)
output << ' '*@level
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
if @ie_hack
output << " "
end
output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
# is less than the specified width, then try to print everything on
# one line
skip = false
if compact
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
string = ""
old_level = @level
@level = 0
node.children.each { |child| write( child, string ) }
@level = old_level
if string.length < @width
output << string
skip = true
end
end
end
unless skip
output << "\n"
@level += @indentation
node.children.each { |child|
next if child.kind_of?(Text) and child.to_s.strip.length == 0
write( child, output )
output << "\n"
}
@level -= @indentation
output << ' '*@level
end
output << "</#{node.expanded_name}"
end
output << ">"
end
def write_text( node, output )
s = node.to_s()
s.gsub!(/\s/,' ')
s.squeeze!(" ")
s = wrap(s, 80-@level)
s = indent_text(s, @level, " ", true)
output << (' '*@level + s)
end
def write_comment( node, output)
output << ' ' * @level
super
end
def write_cdata( node, output)
output << ' ' * @level
super
end
def write_document( node, output )
# Ok, this is a bit odd. All XML documents have an XML declaration,
# but it may not write itself if the user didn't specifically add it,
# either through the API or in the input document. If it doesn't write
# itself, then we don't need a carriage return... which makes this
# logic more complex.
node.children.each { |child|
next if child == node.children[-1] and child.instance_of?(Text)
unless child == node.children[0] or child.instance_of?(Text) or
(child == node.children[1] and !node.children[0].writethis)
output << "\n"
end
write( child, output )
}
end
private
def indent_text(string, level=1, style="\t", indentfirstline=true)
return string if level < 0
string.gsub(/\n/, "\n#{style*level}")
end
def wrap(string, width)
# Recursivly wrap string at width.
return string if string.length <= width
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
end
end
end
end

View file

@ -0,0 +1,56 @@
require 'rexml/formatters/pretty'
module REXML
module Formatters
# The Transitive formatter writes an XML document that parses to an
# identical document as the source document. This means that no extra
# whitespace nodes are inserted, and whitespace within text nodes is
# preserved. Within these constraints, the document is pretty-printed,
# with whitespace inserted into the metadata to introduce formatting.
#
# Note that this is only useful if the original XML is not already
# formatted. Since this formatter does not alter whitespace nodes, the
# results of formatting already formatted XML will be odd.
class Transitive < Default
def initialize( indentation=2 )
@indentation = indentation
@level = 0
end
protected
def write_element( node, output )
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
output << "\n"
output << ' '*@level
if node.children.empty?
output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
# is less than the specified width, then try to print everything on
# one line
skip = false
@level += @indentation
node.children.each { |child|
write( child, output )
}
@level -= @indentation
output << "</#{node.expanded_name}"
output << "\n"
output << ' '*@level
end
output << ">"
end
def write_text( node, output )
output << node.to_s()
end
end
end
end

View file

@ -339,7 +339,6 @@ module REXML
object.to_f object.to_f
else else
str = string( object ) str = string( object )
#puts "STRING OF #{object.inspect} = #{str}"
# If XPath ever gets scientific notation... # If XPath ever gets scientific notation...
#if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/ #if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/
if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/ if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/

View file

@ -38,7 +38,11 @@ module REXML
Instruction.new self Instruction.new self
end end
# == DEPRECATED
# See the rexml/formatters package
#
def write writer, indent=-1, transitive=false, ie_hack=false def write writer, indent=-1, transitive=false, ie_hack=false
Kernel.warn( "#{self.class.name}.write is deprecated" )
indent(writer, indent) indent(writer, indent)
writer << START.sub(/\\/u, '') writer << START.sub(/\\/u, '')
writer << @target writer << @target

View file

@ -1,4 +1,6 @@
require "rexml/parseexception" require "rexml/parseexception"
require "rexml/formatters/pretty"
require "rexml/formatters/default"
module REXML module REXML
# Represents a node in the tree. Nodes are never encountered except as # Represents a node in the tree. Nodes are never encountered except as
@ -18,10 +20,19 @@ module REXML
@parent[ ind - 1 ] @parent[ ind - 1 ]
end end
def to_s indent=-1 # indent::
rv = "" # *DEPRECATED* This parameter is now ignored. See the formatters in the
write rv,indent # REXML::Formatters package for changing the output style.
rv def to_s indent=nil
unless indent.nil?
Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated" )
f = REXML::Formatters::Pretty.new( indent )
f.write( self, rv, indent )
else
f = REXML::Formatters::Default.new
f.write( self, rv = "" )
end
return rv
end end
def indent to, ind def indent to, ind

View file

@ -1,5 +1,7 @@
require 'rexml/parseexception' require 'rexml/parseexception'
require 'rexml/undefinednamespaceexception'
require 'rexml/source' require 'rexml/source'
require 'set'
module REXML module REXML
module Parsers module Parsers
@ -24,7 +26,8 @@ module REXML
# Nat Price gave me some good ideas for the API. # Nat Price gave me some good ideas for the API.
class BaseParser class BaseParser
NCNAME_STR= '[\w:][\-\w\d.]*' NCNAME_STR= '[\w:][\-\w\d.]*'
NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
NAMECHAR = '[\-\w\d\.:]' NAMECHAR = '[\-\w\d\.:]'
NAME = "([\\w:]#{NAMECHAR}*)" NAME = "([\\w:]#{NAMECHAR}*)"
@ -35,7 +38,7 @@ module REXML
DOCTYPE_START = /\A\s*<!DOCTYPE\s/um DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um
COMMENT_START = /\A<!--/u COMMENT_START = /\A<!--/u
COMMENT_PATTERN = /<!--(.*?)-->/um COMMENT_PATTERN = /<!--(.*?)-->/um
CDATA_START = /\A<!\[CDATA\[/u CDATA_START = /\A<!\[CDATA\[/u
@ -45,7 +48,7 @@ module REXML
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
INSTRUCTION_START = /\A<\?/u INSTRUCTION_START = /\A<\?/u
INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um
TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{NAME_STR}\s*=\s*(["']).*?\3)*)\s*(\/)?>/um TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um
CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
@ -53,7 +56,7 @@ module REXML
STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um
ENTITY_START = /^\s*<!ENTITY/ 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_START = /^\s*<!ELEMENT/um
ELEMENTDECL_PATTERN = /^\s*(<!ELEMENT.*?)>/um ELEMENTDECL_PATTERN = /^\s*(<!ELEMENT.*?)>/um
SYSTEMENTITY = /^\s*(%.*?;)\s*$/um SYSTEMENTITY = /^\s*(%.*?;)\s*$/um
@ -133,6 +136,7 @@ module REXML
@tags = [] @tags = []
@stack = [] @stack = []
@entities = [] @entities = []
@nsstack = []
end end
def position def position
@ -188,6 +192,7 @@ module REXML
end end
return [ :end_document ] if empty? return [ :end_document ] if empty?
return @stack.shift if @stack.size > 0 return @stack.shift if @stack.size > 0
#STDERR.puts @source.encoding
@source.read if @source.buffer.size<2 @source.read if @source.buffer.size<2
#STDERR.puts "BUFFER = #{@source.buffer.inspect}" #STDERR.puts "BUFFER = #{@source.buffer.inspect}"
if @document_status == nil if @document_status == nil
@ -213,14 +218,15 @@ module REXML
return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ] return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ]
when DOCTYPE_START when DOCTYPE_START
md = @source.match( DOCTYPE_PATTERN, true ) md = @source.match( DOCTYPE_PATTERN, true )
@nsstack.unshift(curr_ns=Set.new)
identity = md[1] identity = md[1]
close = md[2] close = md[2]
identity =~ IDENTITY identity =~ IDENTITY
name = $1 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 pub_sys = $2.nil? ? nil : $2.strip
long_name = $3.nil? ? nil : $3.strip long_name = $4.nil? ? nil : $4.strip
uri = $4.nil? ? nil : $4.strip uri = $6.nil? ? nil : $6.strip
args = [ :start_doctype, name, pub_sys, long_name, uri ] args = [ :start_doctype, name, pub_sys, long_name, uri ]
if close == ">" if close == ">"
@document_status = :after_doctype @document_status = :after_doctype
@ -288,6 +294,9 @@ module REXML
val = attdef[3] val = attdef[3]
val = attdef[4] if val == "#FIXED " val = attdef[4] if val == "#FIXED "
pairs[attdef[0]] = val pairs[attdef[0]] = val
if attdef[0] =~ /^xmlns:(.*)/
@nsstack[0] << $1
end
end end
end end
return [ :attlistdecl, element, pairs, contents ] return [ :attlistdecl, element, pairs, contents ]
@ -312,6 +321,7 @@ module REXML
begin begin
if @source.buffer[0] == ?< if @source.buffer[0] == ?<
if @source.buffer[1] == ?/ if @source.buffer[1] == ?/
@nsstack.shift
last_tag = @tags.pop last_tag = @tags.pop
#md = @source.match_to_consume( '>', CLOSE_MATCH) #md = @source.match_to_consume( '>', CLOSE_MATCH)
md = @source.match( CLOSE_MATCH, true ) md = @source.match( CLOSE_MATCH, true )
@ -345,19 +355,47 @@ module REXML
raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES ) raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES )
raise REXML::ParseException.new("malformed XML: missing tag start", @source) raise REXML::ParseException.new("malformed XML: missing tag start", @source)
end end
attrs = [] attributes = {}
if md[2].size > 0 prefixes = Set.new
attrs = md[2].scan( ATTRIBUTE_PATTERN ) prefixes << md[2] if md[2]
@nsstack.unshift(curr_ns=Set.new)
if md[4].size > 0
attrs = md[4].scan( ATTRIBUTE_PATTERN )
raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0 raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0
attrs.each { |a,b,c,d,e|
if b == "xmlns"
if c == "xml"
if d != "http://www.w3.org/XML/1998/namespace"
msg = "The 'xml' prefix must not be bound to any other namespace "+
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
raise REXML::ParseException.new( msg, @source, self )
end
elsif c == "xmlns"
msg = "The 'xmlns' prefix must not be declared "+
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
raise REXML::ParseException.new( msg, @source, self)
end
curr_ns << c
elsif b
prefixes << b unless b == "xml"
end
attributes[a] = e
}
end end
if md[4] # Verify that all of the prefixes have been defined
for prefix in prefixes
unless @nsstack.find{|k| k.member?(prefix)}
raise UndefinedNamespaceException.new(prefix,@source,self)
end
end
if md[6]
@closed = md[1] @closed = md[1]
@nsstack.shift
else else
@tags.push( md[1] ) @tags.push( md[1] )
end end
attributes = {}
attrs.each { |a,b,c| attributes[a] = c }
return [ :start_element, md[1], attributes ] return [ :start_element, md[1], attributes ]
end end
else else
@ -371,6 +409,8 @@ module REXML
# return PullEvent.new( :text, md[1], unnormalized ) # return PullEvent.new( :text, md[1], unnormalized )
return [ :text, md[1] ] return [ :text, md[1] ]
end end
rescue REXML::UndefinedNamespaceException
raise
rescue REXML::ParseException rescue REXML::ParseException
raise raise
rescue Exception, NameError => error rescue Exception, NameError => error

View file

@ -94,6 +94,8 @@ module REXML
when :end_document when :end_document
handle( :end_document ) handle( :end_document )
break break
when :start_doctype
handle( :doctype, *event[1..-1])
when :end_doctype when :end_doctype
context = context[1] context = context[1]
when :start_element when :start_element
@ -167,7 +169,7 @@ module REXML
when :entitydecl when :entitydecl
@entities[ event[1] ] = event[2] if event.size == 3 @entities[ event[1] ] = event[2] if event.size == 3
handle( *event ) handle( *event )
when :processing_instruction, :comment, :doctype, :attlistdecl, when :processing_instruction, :comment, :attlistdecl,
:elementdecl, :cdata, :notationdecl, :xmldecl :elementdecl, :cdata, :notationdecl, :xmldecl
handle( *event ) handle( *event )
end end

View file

@ -1,4 +1,5 @@
require 'rexml/validation/validationexception' require 'rexml/validation/validationexception'
require 'rexml/undefinednamespaceexception'
module REXML module REXML
module Parsers module Parsers
@ -29,8 +30,7 @@ module REXML
return return
when :start_element when :start_element
tag_stack.push(event[1]) tag_stack.push(event[1])
# find the observers for namespaces el = @build_context = @build_context.add_element( event[1], event[2] )
@build_context = @build_context.add_element( event[1], event[2] )
when :end_element when :end_element
tag_stack.pop tag_stack.pop
@build_context = @build_context.parent @build_context = @build_context.parent
@ -86,6 +86,8 @@ module REXML
end end
rescue REXML::Validation::ValidationException rescue REXML::Validation::ValidationException
raise raise
rescue REXML::UndefinedNamespaceException
raise
rescue rescue
raise ParseException.new( $!.message, @parser.source, @parser, $! ) raise ParseException.new( $!.message, @parser.source, @parser, $! )
end end

View file

@ -551,7 +551,7 @@ module REXML
end end
end end
#puts "BEFORE WITH '#{rest}'" #puts "BEFORE WITH '#{rest}'"
rest = LocationPath(rest, n) if rest =~ /^[\/\.\@\[\w_*]/ rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/
parsed.concat(n) parsed.concat(n)
return rest return rest
end end

View file

@ -1,3 +1,4 @@
# -*- encoding: utf-8 -*-
# REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby. # REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby.
# #
# REXML is a _pure_ Ruby, XML 1.0 conforming, # REXML is a _pure_ Ruby, XML 1.0 conforming,
@ -10,8 +11,9 @@
# #
# Main page:: http://www.germane-software.com/software/rexml # Main page:: http://www.germane-software.com/software/rexml
# Author:: Sean Russell <serATgermaneHYPHENsoftwareDOTcom> # Author:: Sean Russell <serATgermaneHYPHENsoftwareDOTcom>
# Version:: 3.1.6 # Version:: 3.1.7.2
# Date:: 2006/335 # Date:: 2007/275
# Revision:: $Revision$
# #
# This API documentation can be downloaded from the REXML home page, or can # This API documentation can be downloaded from the REXML home page, or can
# be accessed online[http://www.germane-software.com/software/rexml_doc] # be accessed online[http://www.germane-software.com/software/rexml_doc]
@ -20,9 +22,10 @@
# or can be accessed # or can be accessed
# online[http://www.germane-software.com/software/rexml/docs/tutorial.html] # online[http://www.germane-software.com/software/rexml/docs/tutorial.html]
module REXML module REXML
COPYRIGHT = "Copyright © 2001-2006 Sean Russell <ser@germane-software.com>" COPYRIGHT = "Copyright \xC2\xA9 2001-2006 Sean Russell <ser@germane-software.com>"
DATE = "2006/335" VERSION = "3.1.7.2"
VERSION = "3.1.6" DATE = "2007/275"
REVISION = "$Revision$".gsub(/\$Revision:|\$/,'').strip
Copyright = COPYRIGHT Copyright = COPYRIGHT
Version = VERSION Version = VERSION

View file

@ -18,7 +18,7 @@ module REXML
arg arg
else else
raise "#{arg.class} is not a valid input stream. It must walk \n"+ raise "#{arg.class} is not a valid input stream. It must walk \n"+
"like either a String, IO, or Source." "like either a String, an IO, or a Source."
end end
end end
end end
@ -134,6 +134,7 @@ module REXML
def initialize(arg, block_size=500, encoding=nil) def initialize(arg, block_size=500, encoding=nil)
@er_source = @source = arg @er_source = @source = arg
@to_utf = false @to_utf = false
# Determining the encoding is a deceptively difficult issue to resolve. # Determining the encoding is a deceptively difficult issue to resolve.
# First, we check the first two bytes for UTF-16. Then we # First, we check the first two bytes for UTF-16. Then we
# assume that the encoding is at least ASCII enough for the '>', and # assume that the encoding is at least ASCII enough for the '>', and
@ -145,10 +146,16 @@ module REXML
str = @source.read( 2 ) str = @source.read( 2 )
if encoding if encoding
self.encoding = encoding self.encoding = encoding
elsif /\A(?:\xfe\xff|\xff\xfe)/n =~ str elsif 0xfe == str[0] && 0xff == str[1]
self.encoding = check_encoding( str ) @line_break = "\000>"
elsif 0xff == str[0] && 0xfe == str[1]
@line_break = ">\000"
elsif 0xef == str[0] && 0xbb == str[1]
str += @source.read(1)
str = '' if (0xbf == str[2])
@line_break = ">"
else else
@line_break = '>' @line_break = ">"
end end
super str+@source.readline( @line_break ) super str+@source.readline( @line_break )
end end

View file

@ -211,16 +211,17 @@ module REXML
return new_string return new_string
end end
# == DEPRECATED
# See REXML::Formatters
#
def write( writer, indent=-1, transitive=false, ie_hack=false ) def write( writer, indent=-1, transitive=false, ie_hack=false )
s = to_s() Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters")
if not (@parent and @parent.whitespace) then formatter = if indent > -1
s = wrap(s, 60, false) if @parent and @parent.context[:wordwrap] == :all REXML::Formatters::Pretty.new( indent )
if @parent and not @parent.context[:indentstyle].nil? and indent > 0 and s.count("\n") > 0 else
s = indent_text(s, indent, @parent.context[:indentstyle], false) REXML::Formatters::Default.new
end end
s.squeeze!(" \n\t") if @parent and !@parent.whitespace formatter.write( self, writer )
end
writer << s
end end
# FIXME # FIXME

View file

@ -0,0 +1,8 @@
require 'rexml/parseexception'
module REXML
class UndefinedNamespaceException < ParseException
def initialize( prefix, source, parser )
super( "Undefined prefix #{prefix} found" )
end
end
end

View file

@ -13,7 +13,7 @@ module REXML
STOP = '\?>'; STOP = '\?>';
attr_accessor :version, :standalone attr_accessor :version, :standalone
attr_reader :writeencoding attr_reader :writeencoding, :writethis
def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil) def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil)
@writethis = true @writethis = true
@ -37,9 +37,14 @@ module REXML
XMLDecl.new(self) XMLDecl.new(self)
end end
def write writer, indent=-1, transitive=false, ie_hack=false # indent::
# Ignored. There must be no whitespace before an XML declaration
# transitive::
# Ignored
# ie_hack::
# Ignored
def write(writer, indent=-1, transitive=false, ie_hack=false)
return nil unless @writethis or writer.kind_of? Output return nil unless @writethis or writer.kind_of? Output
indent( writer, indent )
writer << START.sub(/\\/u, '') writer << START.sub(/\\/u, '')
if writer.kind_of? Output if writer.kind_of? Output
writer << " #{content writer.encoding}" writer << " #{content writer.encoding}"

View file

@ -160,6 +160,7 @@ module REXML
node_types = ELEMENTS node_types = ELEMENTS
return nodeset if path_stack.length == 0 || nodeset.length == 0 return nodeset if path_stack.length == 0 || nodeset.length == 0
while path_stack.length > 0 while path_stack.length > 0
#puts "#"*5
#puts "Path stack = #{path_stack.inspect}" #puts "Path stack = #{path_stack.inspect}"
#puts "Nodeset is #{nodeset.inspect}" #puts "Nodeset is #{nodeset.inspect}"
if nodeset.length == 0 if nodeset.length == 0
@ -351,7 +352,8 @@ module REXML
when :following_sibling when :following_sibling
#puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}" #puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}"
results = [] results = []
for node in nodeset nodeset.each do |node|
next if node.parent.nil?
all_siblings = node.parent.children all_siblings = node.parent.children
current_index = all_siblings.index( node ) current_index = all_siblings.index( node )
following_siblings = all_siblings[ current_index+1 .. -1 ] following_siblings = all_siblings[ current_index+1 .. -1 ]
@ -362,13 +364,14 @@ module REXML
when :preceding_sibling when :preceding_sibling
results = [] results = []
for node in nodeset nodeset.each do |node|
next if node.parent.nil?
all_siblings = node.parent.children all_siblings = node.parent.children
current_index = all_siblings.index( node ) current_index = all_siblings.index( node )
preceding_siblings = all_siblings[ 0 .. current_index-1 ].reverse preceding_siblings = all_siblings[ 0, current_index ].reverse
#results += expr( path_stack.dclone, preceding_siblings ) results += preceding_siblings
end end
nodeset = preceding_siblings || [] nodeset = results
node_types = ELEMENTS node_types = ELEMENTS
when :preceding when :preceding
@ -389,15 +392,21 @@ module REXML
node_types = ELEMENTS node_types = ELEMENTS
when :namespace when :namespace
#puts "In :namespace"
new_nodeset = [] new_nodeset = []
prefix = path_stack.shift prefix = path_stack.shift
for node in nodeset for node in nodeset
if (node.node_type == :element or node.node_type == :attribute) if (node.node_type == :element or node.node_type == :attribute)
if (node.node_type == :element) if @namespaces
namespaces = @namespaces
elsif (node.node_type == :element)
namespaces = node.namespaces namespaces = node.namespaces
else else
namespaces = node.element.namesapces namespaces = node.element.namesapces
end end
#puts "Namespaces = #{namespaces.inspect}"
#puts "Prefix = #{prefix.inspect}"
#puts "Node.namespace = #{node.namespace}"
if (node.namespace == namespaces[prefix]) if (node.namespace == namespaces[prefix])
new_nodeset << node new_nodeset << node
end end