From 8935ae596b53e044f77da7ef4e061fc7d11751af Mon Sep 17 00:00:00 2001 From: ser Date: Fri, 8 Sep 2006 01:53:33 +0000 Subject: Merged changes from REXML 3.1.5. The list of bug fixes/enhancements is at: http://www.germane-software.com/projects/rexml/query?status=closed&milestone=3.1.5 Merged Nobu's & DrBrain's changes into REXML head. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@10886 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rexml/comment.rb | 24 ++++++------------------ lib/rexml/element.rb | 23 +++++++++++++++++++++++ lib/rexml/functions.rb | 4 ++-- lib/rexml/parsers/baseparser.rb | 13 ++++++++++++- lib/rexml/parsers/xpathparser.rb | 8 +++++++- lib/rexml/xpath.rb | 14 +++++++------- lib/rexml/xpath_parser.rb | 40 ++++++++++++++++++++++++++-------------- 7 files changed, 83 insertions(+), 43 deletions(-) (limited to 'lib') diff --git a/lib/rexml/comment.rb b/lib/rexml/comment.rb index cb91d47f8c..a4fcb58c8d 100644 --- a/lib/rexml/comment.rb +++ b/lib/rexml/comment.rb @@ -35,31 +35,19 @@ module REXML end # output:: - # Where to write the string + # Where to write the string # indent:: - # An integer. If -1, no indenting will be used; otherwise, the - # indentation will be this number of spaces, and children will be - # indented an additional amount. + # An integer. If -1, no indenting will be used; otherwise, the + # indentation will be this number of spaces, and children will be + # indented an additional amount. # transitive:: - # 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 - # the absolute *value* of the document -- that is, it leaves the value - # and number of Text nodes in the document unchanged. + # Ignored by this class. The contents of comments are never modified. # ie_hack:: - # Internet Explorer is the worst piece of crap to have ever been - # 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. - # + # Needed for conformity to the child API, but not used by this class. def write( output, indent=-1, transitive=false, ie_hack=false ) indent( output, indent ) output << START output << @string - if indent>-1 - output << "\n" - indent( output, indent ) - end output << STOP end diff --git a/lib/rexml/element.rb b/lib/rexml/element.rb index 80463d95b7..435076420a 100644 --- a/lib/rexml/element.rb +++ b/lib/rexml/element.rb @@ -938,6 +938,29 @@ module REXML def each( xpath=nil, &block) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end + + def collect( xpath=nil, &block ) + collection = [] + XPath::each( @element, xpath ) {|e| + collection << yield(e) if e.kind_of?(Element) + } + collection + end + + def inject( xpath=nil, initial=nil, &block ) + first = true + XPath::each( @element, xpath ) {|e| + if (e.kind_of? Element) + if (first and initial == nil) + initial = e + first = false + else + initial = yield( initial, e ) if e.kind_of? Element + end + end + } + initial + end # Returns the number of +Element+ children of the parent object. # doc = Document.new 'seanelliottrussell' diff --git a/lib/rexml/functions.rb b/lib/rexml/functions.rb index c09ffdeae7..d741dbdab7 100644 --- a/lib/rexml/functions.rb +++ b/lib/rexml/functions.rb @@ -326,8 +326,8 @@ module REXML else str = string( object ) #puts "STRING OF #{object.inspect} = #{str}" - if str =~ /^\d+/ - object.to_s.to_f + if str =~ /^-?\.?\d/ + str.to_f else (0.0 / 0.0) end diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb index bce4ba4c20..2cfcf02308 100644 --- a/lib/rexml/parsers/baseparser.rb +++ b/lib/rexml/parsers/baseparser.rb @@ -96,6 +96,13 @@ module REXML "apos" => [/'/, "'", "'", /'/] } + + ###################################################################### + # These are patterns to identify common markup errors, to make the + # error messages more informative. + ###################################################################### + MISSING_ATTRIBUTE_QUOTES = /^<#{NAME_STR}\s+#{NAME_STR}\s*=\s*[^"']/um + def initialize( source ) self.stream = source end @@ -335,7 +342,11 @@ module REXML else # Get the next tag md = @source.match(TAG_MATCH, true) - raise REXML::ParseException.new("malformed XML: missing tag start", @source) unless md + unless md + # Check for 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) + end attrs = [] if md[2].size > 0 attrs = md[2].scan( ATTRIBUTE_PATTERN ) diff --git a/lib/rexml/parsers/xpathparser.rb b/lib/rexml/parsers/xpathparser.rb index 6bac852d6b..6f5b21cd93 100644 --- a/lib/rexml/parsers/xpathparser.rb +++ b/lib/rexml/parsers/xpathparser.rb @@ -596,7 +596,13 @@ module REXML parsed << :function parsed << fname path = FunctionCall(path, parsed) - when LITERAL, NUMBER + when NUMBER + #puts "LITERAL or NUMBER: #$1" + varname = $1.nil? ? $2 : $1 + path = $' + parsed << :literal + parsed << (varname.include?('.') ? varname.to_f : varname.to_i) + when LITERAL #puts "LITERAL or NUMBER: #$1" varname = $1.nil? ? $2 : $1 path = $' diff --git a/lib/rexml/xpath.rb b/lib/rexml/xpath.rb index 1ed440868b..939399e283 100644 --- a/lib/rexml/xpath.rb +++ b/lib/rexml/xpath.rb @@ -19,9 +19,9 @@ module REXML # XPath.first( node ) # XPath.first( doc, "//b"} ) # XPath.first( node, "a/x:b", { "x"=>"http://doofus" } ) - def XPath::first element, path=nil, namespaces={}, variables={} - raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.kind_of? Hash - raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of? Hash + def XPath::first element, path=nil, namespaces=nil, variables={} + raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) + raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables @@ -42,9 +42,9 @@ module REXML # XPath.each( node ) { |el| ... } # XPath.each( node, '/*[@attr='v']' ) { |el| ... } # XPath.each( node, 'ancestor::x' ) { |el| ... } - def XPath::each element, path=nil, namespaces={}, variables={}, &block - raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.kind_of? Hash - raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of? Hash + def XPath::each element, path=nil, namespaces=nil, variables={}, &block + raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) + raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables @@ -54,7 +54,7 @@ module REXML end # Returns an array of nodes matching a given XPath. - def XPath::match element, path=nil, namespaces={}, variables={} + def XPath::match element, path=nil, namespaces=nil, variables={} parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables diff --git a/lib/rexml/xpath_parser.rb b/lib/rexml/xpath_parser.rb index 98ed70cc10..a813236e10 100644 --- a/lib/rexml/xpath_parser.rb +++ b/lib/rexml/xpath_parser.rb @@ -10,9 +10,13 @@ class Object end end class Symbol - def dclone - self - end + def dclone ; self ; end +end +class Fixnum + def dclone ; self ; end +end +class Float + def dclone ; self ; end end class Array def dclone @@ -34,7 +38,7 @@ module REXML def initialize( ) @parser = REXML::Parsers::XPathParser.new - @namespaces = {} + @namespaces = nil @variables = {} end @@ -130,6 +134,21 @@ module REXML private + # Returns a String namespace for a node, given a prefix + # The rules are: + # + # 1. Use the supplied namespace mapping first. + # 2. If no mapping was supplied, use the context node to look up the namespace + def get_namespace( node, prefix ) + if @namespaces + return @namespaces[prefix] || '' + else + return node.namespace( prefix ) if node.node_type == :element + return '' + end + end + + # Expr takes a stack of path elements and a set of nodes (either a Parent # or an Array and returns an Array of matching nodes ALL = [ :attribute, :element, :text, :processing_instruction, :comment ] @@ -152,12 +171,9 @@ module REXML #puts "IN QNAME" prefix = path_stack.shift name = path_stack.shift - default_ns = @namespaces[prefix] - default_ns = default_ns ? default_ns : '' nodeset.delete_if do |node| - ns = default_ns # FIXME: This DOUBLES the time XPath searches take - ns = node.namespace( prefix ) if node.node_type == :element and ns == '' + ns = get_namespace( node, prefix ) #puts "NS = #{ns.inspect}" #puts "node.node_type == :element => #{node.node_type == :element}" if node.node_type == :element @@ -209,11 +225,7 @@ module REXML node_types = ELEMENTS when :literal - literal = path_stack.shift - if literal =~ /^\d+(\.\d+)?$/ - return ($1 ? literal.to_f : literal.to_i) - end - return literal + return path_stack.shift when :attribute new_nodeset = [] @@ -224,7 +236,7 @@ module REXML for element in nodeset if element.node_type == :element #puts element.name - attr = element.attribute( name, @namespaces[prefix] ) + attr = element.attribute( name, get_namespace(element, prefix) ) new_nodeset << attr if attr end end -- cgit v1.2.3