mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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
This commit is contained in:
parent
1838ddd7ae
commit
8935ae596b
7 changed files with 83 additions and 43 deletions
|
@ -35,31 +35,19 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
# 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 indenting 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 by this class. The contents of comments are never modified.
|
||||||
# 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
|
# Needed for conformity to the child API, but not used by this class.
|
||||||
# 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=-1, transitive=false, ie_hack=false )
|
def write( output, indent=-1, transitive=false, ie_hack=false )
|
||||||
indent( output, indent )
|
indent( output, indent )
|
||||||
output << START
|
output << START
|
||||||
output << @string
|
output << @string
|
||||||
if indent>-1
|
|
||||||
output << "\n"
|
|
||||||
indent( output, indent )
|
|
||||||
end
|
|
||||||
output << STOP
|
output << STOP
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -938,6 +938,29 @@ module REXML
|
||||||
def each( xpath=nil, &block)
|
def each( xpath=nil, &block)
|
||||||
XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element }
|
XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element }
|
||||||
end
|
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.
|
# Returns the number of +Element+ children of the parent object.
|
||||||
# doc = Document.new '<a>sean<b/>elliott<b/>russell<b/></a>'
|
# doc = Document.new '<a>sean<b/>elliott<b/>russell<b/></a>'
|
||||||
|
|
|
@ -326,8 +326,8 @@ module REXML
|
||||||
else
|
else
|
||||||
str = string( object )
|
str = string( object )
|
||||||
#puts "STRING OF #{object.inspect} = #{str}"
|
#puts "STRING OF #{object.inspect} = #{str}"
|
||||||
if str =~ /^\d+/
|
if str =~ /^-?\.?\d/
|
||||||
object.to_s.to_f
|
str.to_f
|
||||||
else
|
else
|
||||||
(0.0 / 0.0)
|
(0.0 / 0.0)
|
||||||
end
|
end
|
||||||
|
|
|
@ -96,6 +96,13 @@ module REXML
|
||||||
"apos" => [/'/, "'", "'", /'/]
|
"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 )
|
def initialize( source )
|
||||||
self.stream = source
|
self.stream = source
|
||||||
end
|
end
|
||||||
|
@ -335,7 +342,11 @@ module REXML
|
||||||
else
|
else
|
||||||
# Get the next tag
|
# Get the next tag
|
||||||
md = @source.match(TAG_MATCH, true)
|
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 = []
|
attrs = []
|
||||||
if md[2].size > 0
|
if md[2].size > 0
|
||||||
attrs = md[2].scan( ATTRIBUTE_PATTERN )
|
attrs = md[2].scan( ATTRIBUTE_PATTERN )
|
||||||
|
|
|
@ -596,7 +596,13 @@ module REXML
|
||||||
parsed << :function
|
parsed << :function
|
||||||
parsed << fname
|
parsed << fname
|
||||||
path = FunctionCall(path, parsed)
|
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"
|
#puts "LITERAL or NUMBER: #$1"
|
||||||
varname = $1.nil? ? $2 : $1
|
varname = $1.nil? ? $2 : $1
|
||||||
path = $'
|
path = $'
|
||||||
|
|
|
@ -19,9 +19,9 @@ module REXML
|
||||||
# XPath.first( node )
|
# XPath.first( node )
|
||||||
# XPath.first( doc, "//b"} )
|
# XPath.first( doc, "//b"} )
|
||||||
# XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
|
# XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
|
||||||
def XPath::first element, path=nil, namespaces={}, variables={}
|
def XPath::first element, path=nil, namespaces=nil, variables={}
|
||||||
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.kind_of? Hash
|
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
|
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
|
||||||
parser = XPathParser.new
|
parser = XPathParser.new
|
||||||
parser.namespaces = namespaces
|
parser.namespaces = namespaces
|
||||||
parser.variables = variables
|
parser.variables = variables
|
||||||
|
@ -42,9 +42,9 @@ module REXML
|
||||||
# XPath.each( node ) { |el| ... }
|
# XPath.each( node ) { |el| ... }
|
||||||
# XPath.each( node, '/*[@attr='v']' ) { |el| ... }
|
# XPath.each( node, '/*[@attr='v']' ) { |el| ... }
|
||||||
# XPath.each( node, 'ancestor::x' ) { |el| ... }
|
# XPath.each( node, 'ancestor::x' ) { |el| ... }
|
||||||
def XPath::each element, path=nil, namespaces={}, variables={}, &block
|
def XPath::each element, path=nil, namespaces=nil, variables={}, &block
|
||||||
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.kind_of? Hash
|
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
|
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
|
||||||
parser = XPathParser.new
|
parser = XPathParser.new
|
||||||
parser.namespaces = namespaces
|
parser.namespaces = namespaces
|
||||||
parser.variables = variables
|
parser.variables = variables
|
||||||
|
@ -54,7 +54,7 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of nodes matching a given XPath.
|
# 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 = XPathParser.new
|
||||||
parser.namespaces = namespaces
|
parser.namespaces = namespaces
|
||||||
parser.variables = variables
|
parser.variables = variables
|
||||||
|
|
|
@ -10,9 +10,13 @@ class Object
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
class Symbol
|
class Symbol
|
||||||
def dclone
|
def dclone ; self ; end
|
||||||
self
|
end
|
||||||
end
|
class Fixnum
|
||||||
|
def dclone ; self ; end
|
||||||
|
end
|
||||||
|
class Float
|
||||||
|
def dclone ; self ; end
|
||||||
end
|
end
|
||||||
class Array
|
class Array
|
||||||
def dclone
|
def dclone
|
||||||
|
@ -34,7 +38,7 @@ module REXML
|
||||||
|
|
||||||
def initialize( )
|
def initialize( )
|
||||||
@parser = REXML::Parsers::XPathParser.new
|
@parser = REXML::Parsers::XPathParser.new
|
||||||
@namespaces = {}
|
@namespaces = nil
|
||||||
@variables = {}
|
@variables = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -130,6 +134,21 @@ module REXML
|
||||||
private
|
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
|
# 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
|
# or an Array and returns an Array of matching nodes
|
||||||
ALL = [ :attribute, :element, :text, :processing_instruction, :comment ]
|
ALL = [ :attribute, :element, :text, :processing_instruction, :comment ]
|
||||||
|
@ -152,12 +171,9 @@ module REXML
|
||||||
#puts "IN QNAME"
|
#puts "IN QNAME"
|
||||||
prefix = path_stack.shift
|
prefix = path_stack.shift
|
||||||
name = path_stack.shift
|
name = path_stack.shift
|
||||||
default_ns = @namespaces[prefix]
|
|
||||||
default_ns = default_ns ? default_ns : ''
|
|
||||||
nodeset.delete_if do |node|
|
nodeset.delete_if do |node|
|
||||||
ns = default_ns
|
|
||||||
# FIXME: This DOUBLES the time XPath searches take
|
# 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 "NS = #{ns.inspect}"
|
||||||
#puts "node.node_type == :element => #{node.node_type == :element}"
|
#puts "node.node_type == :element => #{node.node_type == :element}"
|
||||||
if node.node_type == :element
|
if node.node_type == :element
|
||||||
|
@ -209,11 +225,7 @@ module REXML
|
||||||
node_types = ELEMENTS
|
node_types = ELEMENTS
|
||||||
|
|
||||||
when :literal
|
when :literal
|
||||||
literal = path_stack.shift
|
return path_stack.shift
|
||||||
if literal =~ /^\d+(\.\d+)?$/
|
|
||||||
return ($1 ? literal.to_f : literal.to_i)
|
|
||||||
end
|
|
||||||
return literal
|
|
||||||
|
|
||||||
when :attribute
|
when :attribute
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
|
@ -224,7 +236,7 @@ module REXML
|
||||||
for element in nodeset
|
for element in nodeset
|
||||||
if element.node_type == :element
|
if element.node_type == :element
|
||||||
#puts element.name
|
#puts element.name
|
||||||
attr = element.attribute( name, @namespaces[prefix] )
|
attr = element.attribute( name, get_namespace(element, prefix) )
|
||||||
new_nodeset << attr if attr
|
new_nodeset << attr if attr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue