mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Cross-ported the REXML changes (3.0.8) from the development branch to the
stable branch. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@6339 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
db0fac0266
commit
abe1214b3d
12 changed files with 946 additions and 891 deletions
|
@ -146,6 +146,12 @@ module REXML
|
||||||
def node_type
|
def node_type
|
||||||
:attribute
|
:attribute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
rv = ""
|
||||||
|
write( rv )
|
||||||
|
rv
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#vim:ts=2 sw=2 noexpandtab:
|
#vim:ts=2 sw=2 noexpandtab:
|
||||||
|
|
|
@ -59,7 +59,7 @@ module REXML
|
||||||
# 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 )
|
indent( output, indent ) unless transitive
|
||||||
output << START
|
output << START
|
||||||
output << @string
|
output << @string
|
||||||
output << STOP
|
output << STOP
|
||||||
|
|
|
@ -32,11 +32,12 @@ module REXML
|
||||||
# # <!DOCTYPE foo '-//I/Hate/External/IDs'>
|
# # <!DOCTYPE foo '-//I/Hate/External/IDs'>
|
||||||
# dt = DocType.new( doctype_to_clone )
|
# dt = DocType.new( doctype_to_clone )
|
||||||
# # Incomplete. Shallow clone of doctype
|
# # Incomplete. Shallow clone of doctype
|
||||||
# source = Source.new( '<!DOCTYPE foo "bar">' )
|
#
|
||||||
# dt = DocType.new( source )
|
# +Note+ that the constructor:
|
||||||
# # <!DOCTYPE foo "bar">
|
#
|
||||||
# dt = DocType.new( source, some_document )
|
# Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
|
||||||
# # Creates a doctype, and adds to the supplied document
|
#
|
||||||
|
# is _deprecated_. Do not use it. It will probably disappear.
|
||||||
def initialize( first, parent=nil )
|
def initialize( first, parent=nil )
|
||||||
@entities = DEFAULT_ENTITIES
|
@entities = DEFAULT_ENTITIES
|
||||||
@long_name = @uri = nil
|
@long_name = @uri = nil
|
||||||
|
@ -54,6 +55,15 @@ module REXML
|
||||||
@external_id = first[1]
|
@external_id = first[1]
|
||||||
@long_name = first[2]
|
@long_name = first[2]
|
||||||
@uri = first[3]
|
@uri = first[3]
|
||||||
|
elsif first.kind_of? Source
|
||||||
|
super( parent )
|
||||||
|
parser = Parsers::BaseParser.new( first )
|
||||||
|
event = parser.pull
|
||||||
|
if event[0] == :start_doctype
|
||||||
|
@name, @external_id, @long_name, @uri, = event[1..-1]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
super()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -176,68 +176,72 @@ module REXML
|
||||||
tag_stack = []
|
tag_stack = []
|
||||||
in_doctype = false
|
in_doctype = false
|
||||||
entities = nil
|
entities = nil
|
||||||
while true
|
begin
|
||||||
event = parser.pull
|
while true
|
||||||
case event[0]
|
event = parser.pull
|
||||||
when :end_document
|
case event[0]
|
||||||
return
|
when :end_document
|
||||||
when :start_element
|
return
|
||||||
tag_stack.push(event[1])
|
when :start_element
|
||||||
# find the observers for namespaces
|
tag_stack.push(event[1])
|
||||||
build_context = build_context.add_element( event[1], event[2] )
|
# find the observers for namespaces
|
||||||
when :end_element
|
build_context = build_context.add_element( event[1], event[2] )
|
||||||
tag_stack.pop
|
when :end_element
|
||||||
build_context = build_context.parent
|
tag_stack.pop
|
||||||
when :text
|
build_context = build_context.parent
|
||||||
if not in_doctype
|
when :text
|
||||||
if build_context[-1].instance_of? Text
|
if not in_doctype
|
||||||
build_context[-1] << event[1]
|
if build_context[-1].instance_of? Text
|
||||||
else
|
build_context[-1] << event[1]
|
||||||
build_context.add(
|
else
|
||||||
Text.new( event[1], build_context.whitespace, nil, true )
|
build_context.add(
|
||||||
) unless (
|
Text.new( event[1], build_context.whitespace, nil, true )
|
||||||
event[1].strip.size==0 and
|
) unless (
|
||||||
build_context.ignore_whitespace_nodes
|
event[1].strip.size==0 and
|
||||||
)
|
build_context.ignore_whitespace_nodes
|
||||||
end
|
)
|
||||||
end
|
end
|
||||||
when :comment
|
end
|
||||||
c = Comment.new( event[1] )
|
when :comment
|
||||||
build_context.add( c )
|
c = Comment.new( event[1] )
|
||||||
when :cdata
|
build_context.add( c )
|
||||||
c = CData.new( event[1] )
|
when :cdata
|
||||||
build_context.add( c )
|
c = CData.new( event[1] )
|
||||||
when :processing_instruction
|
build_context.add( c )
|
||||||
build_context.add( Instruction.new( event[1], event[2] ) )
|
when :processing_instruction
|
||||||
when :end_doctype
|
build_context.add( Instruction.new( event[1], event[2] ) )
|
||||||
in_doctype = false
|
when :end_doctype
|
||||||
entities.each { |k,v| entities[k] = build_context.entities[k].value }
|
in_doctype = false
|
||||||
build_context = build_context.parent
|
entities.each { |k,v| entities[k] = build_context.entities[k].value }
|
||||||
when :start_doctype
|
build_context = build_context.parent
|
||||||
doctype = DocType.new( event[1..-1], build_context )
|
when :start_doctype
|
||||||
build_context = doctype
|
doctype = DocType.new( event[1..-1], build_context )
|
||||||
entities = {}
|
build_context = doctype
|
||||||
in_doctype = true
|
entities = {}
|
||||||
when :attlistdecl
|
in_doctype = true
|
||||||
n = AttlistDecl.new( event[1..-1] )
|
when :attlistdecl
|
||||||
build_context.add( n )
|
n = AttlistDecl.new( event[1..-1] )
|
||||||
when :externalentity
|
build_context.add( n )
|
||||||
n = ExternalEntity.new( event[1] )
|
when :externalentity
|
||||||
build_context.add( n )
|
n = ExternalEntity.new( event[1] )
|
||||||
when :elementdecl
|
build_context.add( n )
|
||||||
n = ElementDecl.new( event[1] )
|
when :elementdecl
|
||||||
build_context.add(n)
|
n = ElementDecl.new( event[1] )
|
||||||
when :entitydecl
|
build_context.add(n)
|
||||||
entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
|
when :entitydecl
|
||||||
build_context.add(Entity.new(event))
|
entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
|
||||||
when :notationdecl
|
build_context.add(Entity.new(event))
|
||||||
n = NotationDecl.new( *event[1..-1] )
|
when :notationdecl
|
||||||
build_context.add( n )
|
n = NotationDecl.new( *event[1..-1] )
|
||||||
when :xmldecl
|
build_context.add( n )
|
||||||
x = XMLDecl.new( event[1], event[2], event[3] )
|
when :xmldecl
|
||||||
build_context.add( x )
|
x = XMLDecl.new( event[1], event[2], event[3] )
|
||||||
end
|
build_context.add( x )
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
raise ParseException.new( $!.message, parser.source, parser, $! )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,6 +67,22 @@ module REXML
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
rv = "<#@expanded_name"
|
||||||
|
|
||||||
|
@attributes.each_attribute do |attr|
|
||||||
|
rv << " "
|
||||||
|
attr.write( rv, 0 )
|
||||||
|
end unless @attributes.empty?
|
||||||
|
|
||||||
|
if children.size > 0
|
||||||
|
rv << " ... </>"
|
||||||
|
else
|
||||||
|
rv << "/>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# Creates a shallow copy of self.
|
# Creates a shallow copy of self.
|
||||||
# d = Document.new "<a><b/><b/><c><d/></c></a>"
|
# d = Document.new "<a><b/><b/><c><d/></c></a>"
|
||||||
# new_a = d.root.clone
|
# new_a = d.root.clone
|
||||||
|
@ -643,7 +659,7 @@ module REXML
|
||||||
end
|
end
|
||||||
writer << "/"
|
writer << "/"
|
||||||
else
|
else
|
||||||
if transitive and indent>-1 and !@children[0].kind_of? Text
|
if transitive and indent>-1 and !@children[0].instance_of? Text
|
||||||
writer << "\n"
|
writer << "\n"
|
||||||
indent writer, indent+1
|
indent writer, indent+1
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ module REXML
|
||||||
array_utf8 = content.unpack('U*')
|
array_utf8 = content.unpack('U*')
|
||||||
array_enc = []
|
array_enc = []
|
||||||
array_utf8.each do |num|
|
array_utf8.each do |num|
|
||||||
if num <= 0xFF
|
if num <= 0x7F
|
||||||
array_enc << num
|
array_enc << num
|
||||||
else
|
else
|
||||||
# Numeric entity (&#nnnn;); shard by Stefan Scholl
|
# Numeric entity (&#nnnn;); shard by Stefan Scholl
|
||||||
|
|
|
@ -1,366 +1,372 @@
|
||||||
module REXML
|
module REXML
|
||||||
# If you add a method, keep in mind two things:
|
# If you add a method, keep in mind two things:
|
||||||
# (1) the first argument will always be a list of nodes from which to
|
# (1) the first argument will always be a list of nodes from which to
|
||||||
# filter. In the case of context methods (such as position), the function
|
# filter. In the case of context methods (such as position), the function
|
||||||
# should return an array with a value for each child in the array.
|
# should return an array with a value for each child in the array.
|
||||||
# (2) all method calls from XML will have "-" replaced with "_".
|
# (2) all method calls from XML will have "-" replaced with "_".
|
||||||
# Therefore, in XML, "local-name()" is identical (and actually becomes)
|
# Therefore, in XML, "local-name()" is identical (and actually becomes)
|
||||||
# "local_name()"
|
# "local_name()"
|
||||||
module Functions
|
module Functions
|
||||||
@@node = nil
|
@@node = nil
|
||||||
@@index = nil
|
@@index = nil
|
||||||
@@size = nil
|
@@size = nil
|
||||||
@@variables = {}
|
@@variables = {}
|
||||||
@@namespace_context = {}
|
@@namespace_context = {}
|
||||||
|
|
||||||
def Functions::node=(value); @@node = value; end
|
def Functions::node=(value); @@node = value; end
|
||||||
def Functions::index=(value); @@index = value; end
|
def Functions::index=(value); @@index = value; end
|
||||||
def Functions::size=(value); @@size = value; end
|
def Functions::size=(value); @@size = value; end
|
||||||
def Functions::variables=(value); @@variables = value; end
|
def Functions::variables=(value); @@variables = value; end
|
||||||
def Functions::namespace_context=(value)
|
def Functions::namespace_context=(value)
|
||||||
@@namespace_context = value
|
@@namespace_context = value
|
||||||
end
|
end
|
||||||
def Functions::node; @@node; end
|
def Functions::node; @@node; end
|
||||||
def Functions::index; @@index; end
|
def Functions::index; @@index; end
|
||||||
def Functions::size; @@size; end
|
def Functions::size; @@size; end
|
||||||
def Functions::variables; @@variables; end
|
def Functions::variables; @@variables; end
|
||||||
def Functions::namespace_context; @@namespace_context; end
|
def Functions::namespace_context; @@namespace_context; end
|
||||||
|
|
||||||
def Functions::text( )
|
def Functions::text( )
|
||||||
if @@node.node_type == :element
|
if @@node.node_type == :element
|
||||||
return @@node.text
|
return @@node.text
|
||||||
elsif @@node.node_type == :text
|
elsif @@node.node_type == :text
|
||||||
return @@node.value
|
return @@node.value
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::last( )
|
def Functions::last( )
|
||||||
@@size
|
@@size
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::position( )
|
def Functions::position( )
|
||||||
@@index
|
@@index
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::count( node_set )
|
def Functions::count( node_set )
|
||||||
node_set.size
|
node_set.size
|
||||||
end
|
end
|
||||||
|
|
||||||
# Since REXML is non-validating, this method is not implemented as it
|
# Since REXML is non-validating, this method is not implemented as it
|
||||||
# requires a DTD
|
# requires a DTD
|
||||||
def Functions::id( object )
|
def Functions::id( object )
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::local_name( node_set=nil )
|
def Functions::local_name( node_set=nil )
|
||||||
get_namespace( node_set ) do |node|
|
get_namespace( node_set ) do |node|
|
||||||
return node.local_name
|
return node.local_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::namespace_uri( node_set=nil )
|
def Functions::namespace_uri( node_set=nil )
|
||||||
get_namespace( node_set ) {|node| node.namespace}
|
get_namespace( node_set ) {|node| node.namespace}
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::name( node_set=nil )
|
def Functions::name( node_set=nil )
|
||||||
get_namespace( node_set ) do |node|
|
get_namespace( node_set ) do |node|
|
||||||
node.expanded_name
|
node.expanded_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper method.
|
# Helper method.
|
||||||
def Functions::get_namespace( node_set = nil )
|
def Functions::get_namespace( node_set = nil )
|
||||||
if node_set == nil
|
if node_set == nil
|
||||||
yield @@node if defined? @@node.namespace
|
yield @@node if defined? @@node.namespace
|
||||||
else
|
else
|
||||||
if node_set.namespace
|
if node_set.namespace
|
||||||
yield node_set
|
yield node_set
|
||||||
else
|
else
|
||||||
return unless node_set.kind_of? Enumerable
|
return unless node_set.kind_of? Enumerable
|
||||||
node_set.each { |node| yield node if defined? node.namespace }
|
node_set.each { |node| yield node if defined? node.namespace }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# A node-set is converted to a string by returning the string-value of the
|
# A node-set is converted to a string by returning the string-value of the
|
||||||
# node in the node-set that is first in document order. If the node-set is
|
# node in the node-set that is first in document order. If the node-set is
|
||||||
# empty, an empty string is returned.
|
# empty, an empty string is returned.
|
||||||
#
|
#
|
||||||
# A number is converted to a string as follows
|
# A number is converted to a string as follows
|
||||||
#
|
#
|
||||||
# NaN is converted to the string NaN
|
# NaN is converted to the string NaN
|
||||||
#
|
#
|
||||||
# positive zero is converted to the string 0
|
# positive zero is converted to the string 0
|
||||||
#
|
#
|
||||||
# negative zero is converted to the string 0
|
# negative zero is converted to the string 0
|
||||||
#
|
#
|
||||||
# positive infinity is converted to the string Infinity
|
# positive infinity is converted to the string Infinity
|
||||||
#
|
#
|
||||||
# negative infinity is converted to the string -Infinity
|
# negative infinity is converted to the string -Infinity
|
||||||
#
|
#
|
||||||
# if the number is an integer, the number is represented in decimal form
|
# if the number is an integer, the number is represented in decimal form
|
||||||
# as a Number with no decimal point and no leading zeros, preceded by a
|
# as a Number with no decimal point and no leading zeros, preceded by a
|
||||||
# minus sign (-) if the number is negative
|
# minus sign (-) if the number is negative
|
||||||
#
|
#
|
||||||
# otherwise, the number is represented in decimal form as a Number
|
# otherwise, the number is represented in decimal form as a Number
|
||||||
# including a decimal point with at least one digit before the decimal
|
# including a decimal point with at least one digit before the decimal
|
||||||
# point and at least one digit after the decimal point, preceded by a
|
# point and at least one digit after the decimal point, preceded by a
|
||||||
# minus sign (-) if the number is negative; there must be no leading zeros
|
# minus sign (-) if the number is negative; there must be no leading zeros
|
||||||
# before the decimal point apart possibly from the one required digit
|
# before the decimal point apart possibly from the one required digit
|
||||||
# immediately before the decimal point; beyond the one required digit
|
# immediately before the decimal point; beyond the one required digit
|
||||||
# after the decimal point there must be as many, but only as many, more
|
# after the decimal point there must be as many, but only as many, more
|
||||||
# digits as are needed to uniquely distinguish the number from all other
|
# digits as are needed to uniquely distinguish the number from all other
|
||||||
# IEEE 754 numeric values.
|
# IEEE 754 numeric values.
|
||||||
#
|
#
|
||||||
# The boolean false value is converted to the string false. The boolean
|
# The boolean false value is converted to the string false. The boolean
|
||||||
# true value is converted to the string true.
|
# true value is converted to the string true.
|
||||||
#
|
#
|
||||||
# An object of a type other than the four basic types is converted to a
|
# An object of a type other than the four basic types is converted to a
|
||||||
# string in a way that is dependent on that type.
|
# string in a way that is dependent on that type.
|
||||||
def Functions::string( object=nil )
|
def Functions::string( object=nil )
|
||||||
#object = @context unless object
|
#object = @context unless object
|
||||||
if object.instance_of? Array
|
if object.instance_of? Array
|
||||||
string( object[0] )
|
string( object[0] )
|
||||||
elsif defined? object.node_type
|
elsif defined? object.node_type
|
||||||
if object.node_type == :attribute
|
if object.node_type == :attribute
|
||||||
object.value
|
object.value
|
||||||
elsif object.node_type == :element
|
elsif object.node_type == :element
|
||||||
object.text
|
object.text
|
||||||
else
|
else
|
||||||
object.to_s
|
object.to_s
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
object.to_s
|
object.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::concat( *objects )
|
def Functions::concat( *objects )
|
||||||
objects.join
|
objects.join
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fixed by Mike Stok
|
# Fixed by Mike Stok
|
||||||
def Functions::starts_with( string, test )
|
def Functions::starts_with( string, test )
|
||||||
string(string).index(string(test)) == 0
|
string(string).index(string(test)) == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fixed by Mike Stok
|
# Fixed by Mike Stok
|
||||||
def Functions::contains( string, test )
|
def Functions::contains( string, test )
|
||||||
string(string).include? string(test)
|
string(string).include? string(test)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Kouhei fixed this
|
# Kouhei fixed this
|
||||||
def Functions::substring_before( string, test )
|
def Functions::substring_before( string, test )
|
||||||
ruby_string = string(string)
|
ruby_string = string(string)
|
||||||
ruby_index = ruby_string.index(string(test))
|
ruby_index = ruby_string.index(string(test))
|
||||||
if ruby_index.nil?
|
if ruby_index.nil?
|
||||||
""
|
""
|
||||||
else
|
else
|
||||||
ruby_string[ 0...ruby_index ]
|
ruby_string[ 0...ruby_index ]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Kouhei fixed this too
|
# Kouhei fixed this too
|
||||||
def Functions::substring_after( string, test )
|
def Functions::substring_after( string, test )
|
||||||
ruby_string = string(string)
|
ruby_string = string(string)
|
||||||
ruby_index = ruby_string.index(string(test))
|
ruby_index = ruby_string.index(string(test))
|
||||||
if ruby_index.nil?
|
if ruby_index.nil?
|
||||||
""
|
""
|
||||||
else
|
else
|
||||||
ruby_string[ ruby_index+1..-1 ]
|
ruby_string[ ruby_index+1..-1 ]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Take equal portions of Mike Stok and Sean Russell; mix
|
# Take equal portions of Mike Stok and Sean Russell; mix
|
||||||
# vigorously, and pour into a tall, chilled glass. Serves 10,000.
|
# vigorously, and pour into a tall, chilled glass. Serves 10,000.
|
||||||
def Functions::substring( string, start, length=nil )
|
def Functions::substring( string, start, length=nil )
|
||||||
ruby_string = string(string)
|
ruby_string = string(string)
|
||||||
ruby_length = if length.nil?
|
ruby_length = if length.nil?
|
||||||
ruby_string.length.to_f
|
ruby_string.length.to_f
|
||||||
else
|
else
|
||||||
number(length)
|
number(length)
|
||||||
end
|
end
|
||||||
ruby_start = number(start)
|
ruby_start = number(start)
|
||||||
|
|
||||||
# Handle the special cases
|
# Handle the special cases
|
||||||
return '' if (
|
return '' if (
|
||||||
ruby_length.nan? or
|
ruby_length.nan? or
|
||||||
ruby_start.nan? or
|
ruby_start.nan? or
|
||||||
ruby_start.infinite?
|
ruby_start.infinite?
|
||||||
)
|
)
|
||||||
|
|
||||||
infinite_length = ruby_length.infinite? == 1
|
infinite_length = ruby_length.infinite? == 1
|
||||||
ruby_length = ruby_string.length if infinite_length
|
ruby_length = ruby_string.length if infinite_length
|
||||||
|
|
||||||
# Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
|
# Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
|
||||||
# are 0..length. Therefore, we have to offset the bounds by one.
|
# are 0..length. Therefore, we have to offset the bounds by one.
|
||||||
ruby_start = ruby_start.round - 1
|
ruby_start = ruby_start.round - 1
|
||||||
ruby_length = ruby_length.round
|
ruby_length = ruby_length.round
|
||||||
|
|
||||||
if ruby_start < 0
|
if ruby_start < 0
|
||||||
ruby_length += ruby_start unless infinite_length
|
ruby_length += ruby_start unless infinite_length
|
||||||
ruby_start = 0
|
ruby_start = 0
|
||||||
end
|
end
|
||||||
return '' if ruby_length <= 0
|
return '' if ruby_length <= 0
|
||||||
ruby_string[ruby_start,ruby_length]
|
ruby_string[ruby_start,ruby_length]
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::string_length( string )
|
def Functions::string_length( string )
|
||||||
string(string).length
|
string(string).length
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::normalize_space( string=nil )
|
def Functions::normalize_space( string=nil )
|
||||||
string = string(@@node) if string.nil?
|
string = string(@@node) if string.nil?
|
||||||
if string.kind_of? Array
|
if string.kind_of? Array
|
||||||
string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
|
string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
|
||||||
else
|
else
|
||||||
string.to_s.strip.gsub(/\s+/um, ' ')
|
string.to_s.strip.gsub(/\s+/um, ' ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is entirely Mike Stok's beast
|
# This is entirely Mike Stok's beast
|
||||||
def Functions::translate( string, tr1, tr2 )
|
def Functions::translate( string, tr1, tr2 )
|
||||||
from = string(tr1)
|
from = string(tr1)
|
||||||
to = string(tr2)
|
to = string(tr2)
|
||||||
|
|
||||||
# the map is our translation table.
|
# the map is our translation table.
|
||||||
#
|
#
|
||||||
# if a character occurs more than once in the
|
# if a character occurs more than once in the
|
||||||
# from string then we ignore the second &
|
# from string then we ignore the second &
|
||||||
# subsequent mappings
|
# subsequent mappings
|
||||||
#
|
#
|
||||||
# if a charactcer maps to nil then we delete it
|
# if a charactcer maps to nil then we delete it
|
||||||
# in the output. This happens if the from
|
# in the output. This happens if the from
|
||||||
# string is longer than the to string
|
# string is longer than the to string
|
||||||
#
|
#
|
||||||
# there's nothing about - or ^ being special in
|
# there's nothing about - or ^ being special in
|
||||||
# http://www.w3.org/TR/xpath#function-translate
|
# http://www.w3.org/TR/xpath#function-translate
|
||||||
# so we don't build ranges or negated classes
|
# so we don't build ranges or negated classes
|
||||||
|
|
||||||
map = Hash.new
|
map = Hash.new
|
||||||
0.upto(from.length - 1) { |pos|
|
0.upto(from.length - 1) { |pos|
|
||||||
from_char = from[pos]
|
from_char = from[pos]
|
||||||
unless map.has_key? from_char
|
unless map.has_key? from_char
|
||||||
map[from_char] =
|
map[from_char] =
|
||||||
if pos < to.length
|
if pos < to.length
|
||||||
to[pos]
|
to[pos]
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
string(string).unpack('U*').collect { |c|
|
string(string).unpack('U*').collect { |c|
|
||||||
if map.has_key? c then map[c] else c end
|
if map.has_key? c then map[c] else c end
|
||||||
}.compact.pack('U*')
|
}.compact.pack('U*')
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::boolean( object=nil )
|
def Functions::boolean( object=nil )
|
||||||
if object.kind_of? String
|
if object.kind_of? String
|
||||||
if object =~ /\d+/u
|
if object =~ /\d+/u
|
||||||
return object.to_f != 0
|
return object.to_f != 0
|
||||||
else
|
else
|
||||||
return object.size > 0
|
return object.size > 0
|
||||||
end
|
end
|
||||||
elsif object.kind_of? Array
|
elsif object.kind_of? Array
|
||||||
object = object.find{|x| x and true}
|
object = object.find{|x| x and true}
|
||||||
end
|
end
|
||||||
return object ? true : false
|
return object ? true : false
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::not( object )
|
def Functions::not( object )
|
||||||
not boolean( object )
|
not boolean( object )
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::true( )
|
def Functions::true( )
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::false( )
|
def Functions::false( )
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
# UNTESTED
|
# UNTESTED
|
||||||
def Functions::lang( language )
|
def Functions::lang( language )
|
||||||
lang = false
|
lang = false
|
||||||
node = @@node
|
node = @@node
|
||||||
attr = nil
|
attr = nil
|
||||||
until node.nil?
|
until node.nil?
|
||||||
if node.node_type == :element
|
if node.node_type == :element
|
||||||
attr = node.attributes["xml:lang"]
|
attr = node.attributes["xml:lang"]
|
||||||
unless attr.nil?
|
unless attr.nil?
|
||||||
lang = compare_language(string(language), attr)
|
lang = compare_language(string(language), attr)
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
node = node.parent
|
node = node.parent
|
||||||
end
|
end
|
||||||
lang
|
lang
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::compare_language lang1, lang2
|
def Functions::compare_language lang1, lang2
|
||||||
lang2.downcase.index(lang1.downcase) == 0
|
lang2.downcase.index(lang1.downcase) == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
# a string that consists of optional whitespace followed by an optional
|
# a string that consists of optional whitespace followed by an optional
|
||||||
# minus sign followed by a Number followed by whitespace is converted to
|
# minus sign followed by a Number followed by whitespace is converted to
|
||||||
# the IEEE 754 number that is nearest (according to the IEEE 754
|
# the IEEE 754 number that is nearest (according to the IEEE 754
|
||||||
# round-to-nearest rule) to the mathematical value represented by the
|
# round-to-nearest rule) to the mathematical value represented by the
|
||||||
# string; any other string is converted to NaN
|
# string; any other string is converted to NaN
|
||||||
#
|
#
|
||||||
# boolean true is converted to 1; boolean false is converted to 0
|
# boolean true is converted to 1; boolean false is converted to 0
|
||||||
#
|
#
|
||||||
# a node-set is first converted to a string as if by a call to the string
|
# a node-set is first converted to a string as if by a call to the string
|
||||||
# function and then converted in the same way as a string argument
|
# function and then converted in the same way as a string argument
|
||||||
#
|
#
|
||||||
# an object of a type other than the four basic types is converted to a
|
# an object of a type other than the four basic types is converted to a
|
||||||
# number in a way that is dependent on that type
|
# number in a way that is dependent on that type
|
||||||
def Functions::number( object=nil )
|
def Functions::number( object=nil )
|
||||||
object = @@node unless object
|
object = @@node unless object
|
||||||
if object == true
|
if object == true
|
||||||
Float(1)
|
Float(1)
|
||||||
elsif object == false
|
elsif object == false
|
||||||
Float(0)
|
Float(0)
|
||||||
elsif object.kind_of? Array
|
elsif object.kind_of? Array
|
||||||
string( object ).to_f
|
number(string( object ))
|
||||||
elsif object.kind_of? Float
|
elsif object.kind_of? Float
|
||||||
object
|
object
|
||||||
else
|
else
|
||||||
object.to_s.to_f
|
str = string( object )
|
||||||
end
|
#puts "STRING OF #{object.inspect} = #{str}"
|
||||||
end
|
if str =~ /^\d+/
|
||||||
|
object.to_s.to_f
|
||||||
|
else
|
||||||
|
(0.0 / 0.0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def Functions::sum( nodes )
|
def Functions::sum( nodes )
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::floor( number )
|
def Functions::floor( number )
|
||||||
number(number).floor
|
number(number).floor
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::ceiling( number )
|
def Functions::ceiling( number )
|
||||||
number(number).ceil
|
number(number).ceil
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::round( number )
|
def Functions::round( number )
|
||||||
begin
|
begin
|
||||||
number(number).round
|
number(number).round
|
||||||
rescue FloatDomainError
|
rescue FloatDomainError
|
||||||
number(number)
|
number(number)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def Functions::method_missing( id )
|
def Functions::method_missing( id )
|
||||||
puts "METHOD MISSING #{id.id2name}"
|
puts "METHOD MISSING #{id.id2name}"
|
||||||
XPath.match( @@node, id.id2name )
|
XPath.match( @@node, id.id2name )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,49 +1,51 @@
|
||||||
module REXML
|
module REXML
|
||||||
class ParseException < RuntimeError
|
class ParseException < RuntimeError
|
||||||
attr_accessor :source, :parser, :continued_exception
|
attr_accessor :source, :parser, :continued_exception
|
||||||
|
|
||||||
def initialize( message, source=nil, parser=nil, exception=nil )
|
def initialize( message, source=nil, parser=nil, exception=nil )
|
||||||
super(message)
|
super(message)
|
||||||
@source = source
|
@source = source
|
||||||
@parser = parser
|
@parser = parser
|
||||||
@continued_exception = exception
|
@continued_exception = exception
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
# Quote the original exception, if there was one
|
# Quote the original exception, if there was one
|
||||||
if @continued_exception
|
if @continued_exception
|
||||||
err = @continued_exception.inspect
|
err = @continued_exception.inspect
|
||||||
err << "\n"
|
err << "\n"
|
||||||
err << @continued_exception.backtrace.join("\n")
|
err << @continued_exception.backtrace.join("\n")
|
||||||
err << "\n...\n"
|
err << "\n...\n"
|
||||||
else
|
else
|
||||||
err = ""
|
err = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the stack trace and error message
|
# Get the stack trace and error message
|
||||||
err << super
|
err << super
|
||||||
|
|
||||||
# Add contextual information
|
# Add contextual information
|
||||||
if @source
|
if @source
|
||||||
err << "\nLine: #{line}\n"
|
err << "\nLine: #{line}\n"
|
||||||
err << "Position: #{position}\n"
|
err << "Position: #{position}\n"
|
||||||
err << "Last 80 unconsumed characters:\n"
|
err << "Last 80 unconsumed characters:\n"
|
||||||
err << @source.buffer[0..80].gsub(/\n/, ' ')
|
err << @source.buffer[0..80].gsub(/\n/, ' ')
|
||||||
end
|
end
|
||||||
|
|
||||||
err
|
err
|
||||||
end
|
end
|
||||||
|
|
||||||
def position
|
def position
|
||||||
@source.current_line[0] if @source and @source.current_line
|
@source.current_line[0] if @source and defined? @source.current_line and
|
||||||
end
|
@source.current_line
|
||||||
|
end
|
||||||
|
|
||||||
def line
|
def line
|
||||||
@source.current_line[2] if @source and @source.current_line
|
@source.current_line[2] if @source and defined? @source.current_line and
|
||||||
end
|
@source.current_line
|
||||||
|
end
|
||||||
|
|
||||||
def context
|
def context
|
||||||
@source.current_line
|
@source.current_line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -100,6 +100,8 @@ module REXML
|
||||||
self.stream = source
|
self.stream = source
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_reader :source
|
||||||
|
|
||||||
def stream=( source )
|
def stream=( source )
|
||||||
if source.kind_of? String
|
if source.kind_of? String
|
||||||
@source = Source.new(source)
|
@source = Source.new(source)
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#
|
#
|
||||||
# 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.0.4
|
# Version:: @ANT_VERSION@
|
||||||
# Date:: +2004/115
|
# Date:: @ANT_DATE@
|
||||||
#
|
#
|
||||||
# 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]
|
||||||
|
@ -21,6 +21,6 @@
|
||||||
# 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, 2002, 2003, 2004 Sean Russell <ser@germane-software.com>"
|
Copyright = "Copyright © 2001, 2002, 2003, 2004 Sean Russell <ser@germane-software.com>"
|
||||||
Date = "+2004/115"
|
Date = "@ANT_DATE@"
|
||||||
Version = "3.0.4"
|
Version = "@ANT_VERSION@"
|
||||||
end
|
end
|
||||||
|
|
|
@ -194,7 +194,7 @@ module REXML
|
||||||
@raw = false
|
@raw = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def indent(string, level=1, style="\t", indentfirstline=true)
|
def indent_text(string, level=1, style="\t", indentfirstline=true)
|
||||||
return string if level < 0
|
return string if level < 0
|
||||||
new_string = ''
|
new_string = ''
|
||||||
string.each { |line|
|
string.each { |line|
|
||||||
|
@ -211,7 +211,7 @@ module REXML
|
||||||
if not (@parent and @parent.whitespace) then
|
if not (@parent and @parent.whitespace) then
|
||||||
s = wrap(s, 60, false) if @parent and @parent.context[:wordwrap] == :all
|
s = wrap(s, 60, false) if @parent and @parent.context[:wordwrap] == :all
|
||||||
if @parent and not @parent.context[:indentstyle].nil? and indent > 0 and s.count("\n") > 0
|
if @parent and not @parent.context[:indentstyle].nil? and indent > 0 and s.count("\n") > 0
|
||||||
s = indent(s, indent, @parent.context[:indentstyle], false)
|
s = indent_text(s, indent, @parent.context[:indentstyle], false)
|
||||||
end
|
end
|
||||||
s.squeeze!(" \n\t") if @parent and !@parent.whitespace
|
s.squeeze!(" \n\t") if @parent and !@parent.whitespace
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,309 +3,308 @@ require 'rexml/xmltokens'
|
||||||
require 'rexml/parsers/xpathparser'
|
require 'rexml/parsers/xpathparser'
|
||||||
|
|
||||||
module REXML
|
module REXML
|
||||||
# You don't want to use this class. Really. Use XPath, which is a wrapper
|
# You don't want to use this class. Really. Use XPath, which is a wrapper
|
||||||
# for this class. Believe me. You don't want to poke around in here.
|
# for this class. Believe me. You don't want to poke around in here.
|
||||||
# There is strange, dark magic at work in this code. Beware. Go back! Go
|
# There is strange, dark magic at work in this code. Beware. Go back! Go
|
||||||
# back while you still can!
|
# back while you still can!
|
||||||
class XPathParser
|
class XPathParser
|
||||||
include XMLTokens
|
include XMLTokens
|
||||||
LITERAL = /^'([^']*)'|^"([^"]*)"/u
|
LITERAL = /^'([^']*)'|^"([^"]*)"/u
|
||||||
|
|
||||||
def initialize( )
|
def initialize( )
|
||||||
@parser = REXML::Parsers::XPathParser.new
|
@parser = REXML::Parsers::XPathParser.new
|
||||||
@namespaces = {}
|
@namespaces = {}
|
||||||
@variables = {}
|
@variables = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def namespaces=( namespaces={} )
|
def namespaces=( namespaces={} )
|
||||||
Functions::namespace_context = namespaces
|
Functions::namespace_context = namespaces
|
||||||
@namespaces = namespaces
|
@namespaces = namespaces
|
||||||
end
|
end
|
||||||
|
|
||||||
def variables=( vars={} )
|
def variables=( vars={} )
|
||||||
Functions::variables = vars
|
Functions::variables = vars
|
||||||
@variables = vars
|
@variables = vars
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse path, nodeset
|
def parse path, nodeset
|
||||||
path_stack = @parser.parse( path )
|
path_stack = @parser.parse( path )
|
||||||
#puts "PARSE: #{path} => #{path_stack.inspect}"
|
#puts "PARSE: #{path} => #{path_stack.inspect}"
|
||||||
#puts "PARSE: nodeset = #{nodeset.collect{|x|x.to_s}.inspect}"
|
#puts "PARSE: nodeset = #{nodeset.collect{|x|x.to_s}.inspect}"
|
||||||
match( path_stack, nodeset )
|
match( path_stack, nodeset )
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicate path, nodeset
|
def predicate path, nodeset
|
||||||
path_stack = @parser.predicate( path )
|
path_stack = @parser.predicate( path )
|
||||||
return Predicate( path_stack, nodeset )
|
return Predicate( path_stack, nodeset )
|
||||||
end
|
end
|
||||||
|
|
||||||
def []=( variable_name, value )
|
def []=( variable_name, value )
|
||||||
@variables[ variable_name ] = value
|
@variables[ variable_name ] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def match( path_stack, nodeset )
|
def match( path_stack, nodeset )
|
||||||
while ( path_stack.size > 0 and nodeset.size > 0 )
|
while ( path_stack.size > 0 and nodeset.size > 0 )
|
||||||
#puts "PARSE: #{path_stack.inspect} '#{nodeset.collect{|n|n.class}.inspect}'"
|
#puts "PARSE: #{path_stack.inspect} '#{nodeset.collect{|n|n.class}.inspect}'"
|
||||||
nodeset = internal_parse( path_stack, nodeset )
|
nodeset = internal_parse( path_stack, nodeset )
|
||||||
#puts "NODESET: #{nodeset.size}"
|
#puts "NODESET: #{nodeset}"
|
||||||
#puts "PATH_STACK: #{path_stack.inspect}"
|
#puts "PATH_STACK: #{path_stack.inspect}"
|
||||||
end
|
end
|
||||||
nodeset
|
nodeset
|
||||||
end
|
end
|
||||||
|
|
||||||
def internal_parse path_stack, nodeset
|
def internal_parse path_stack, nodeset
|
||||||
#puts "INTERNAL_PARSE RETURNING WITH NO RESULTS" if nodeset.size == 0 or path_stack.size == 0
|
#puts "INTERNAL_PARSE RETURNING WITH NO RESULTS" if nodeset.size == 0 or path_stack.size == 0
|
||||||
return nodeset if nodeset.size == 0 or path_stack.size == 0
|
return nodeset if nodeset.size == 0 or path_stack.size == 0
|
||||||
#puts "INTERNAL_PARSE: #{path_stack.inspect}, #{nodeset.collect{|n| n.class}.inspect}"
|
#puts "INTERNAL_PARSE: #{path_stack.inspect}, #{nodeset.collect{|n| n.class}.inspect}"
|
||||||
case path_stack.shift
|
case path_stack.shift
|
||||||
when :document
|
when :document
|
||||||
return [ nodeset[0].root.parent ]
|
return [ nodeset[0].root.parent ]
|
||||||
|
|
||||||
when :qname
|
when :qname
|
||||||
prefix = path_stack.shift
|
prefix = path_stack.shift
|
||||||
name = path_stack.shift
|
name = path_stack.shift
|
||||||
#puts "QNAME #{prefix}#{prefix.size>0?':':''}#{name}"
|
#puts "QNAME #{prefix}#{prefix.size>0?':':''}#{name}"
|
||||||
n = nodeset.clone
|
n = nodeset.clone
|
||||||
ns = @namespaces[prefix]
|
ns = @namespaces[prefix]
|
||||||
ns = ns ? ns : ''
|
ns = ns ? ns : ''
|
||||||
n.delete_if do |node|
|
n.delete_if do |node|
|
||||||
# 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 = node.namespace( prefix ) if node.node_type == :element and ns == ''
|
||||||
#puts "NODE: '#{node.to_s}'; node.has_name?( #{name.inspect}, #{ns.inspect} ): #{ node.has_name?( name, ns )}; node.namespace() = #{node.namespace().inspect}; node.prefix = #{node.prefix().inspect}" if node.node_type == :element
|
#puts "NODE: '#{node.to_s}'; node.has_name?( #{name.inspect}, #{ns.inspect} ): #{ node.has_name?( name, ns )}; node.namespace() = #{node.namespace().inspect}; node.prefix = #{node.prefix().inspect}" if node.node_type == :element
|
||||||
!(node.node_type == :element and node.name == name and node.namespace == ns )
|
!(node.node_type == :element and node.name == name and node.namespace == ns )
|
||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
|
|
||||||
when :any
|
when :any
|
||||||
n = nodeset.clone
|
n = nodeset.clone
|
||||||
n.delete_if { |node| node.node_type != :element }
|
n.delete_if { |node| node.node_type != :element }
|
||||||
return n
|
return n
|
||||||
|
|
||||||
when :self
|
when :self
|
||||||
# THIS SPACE LEFT INTENTIONALLY BLANK
|
# THIS SPACE LEFT INTENTIONALLY BLANK
|
||||||
|
|
||||||
when :processing_instruction
|
when :processing_instruction
|
||||||
target = path_stack.shift
|
target = path_stack.shift
|
||||||
n = nodeset.clone
|
n = nodeset.clone
|
||||||
n.delete_if do |node|
|
n.delete_if do |node|
|
||||||
(node.node_type != :processing_instruction) or
|
(node.node_type != :processing_instruction) or
|
||||||
( !target.nil? and ( node.target != target ) )
|
( !target.nil? and ( node.target != target ) )
|
||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
|
|
||||||
when :text
|
when :text
|
||||||
#puts ":TEXT"
|
#puts ":TEXT"
|
||||||
n = nodeset.clone
|
n = nodeset.clone
|
||||||
n.delete_if do |node|
|
n.delete_if do |node|
|
||||||
#puts "#{node} :: #{node.node_type}"
|
#puts "#{node} :: #{node.node_type}"
|
||||||
node.node_type != :text
|
node.node_type != :text
|
||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
|
|
||||||
when :comment
|
when :comment
|
||||||
n = nodeset.clone
|
n = nodeset.clone
|
||||||
n.delete_if do |node|
|
n.delete_if do |node|
|
||||||
node.node_type != :comment
|
node.node_type != :comment
|
||||||
end
|
end
|
||||||
return n
|
return n
|
||||||
|
|
||||||
when :node
|
when :node
|
||||||
return nodeset
|
return nodeset
|
||||||
|
|
||||||
# FIXME: I suspect the following XPath will fail:
|
# FIXME: I suspect the following XPath will fail:
|
||||||
# /a/*/*[1]
|
# /a/*/*[1]
|
||||||
when :child
|
when :child
|
||||||
#puts "CHILD"
|
#puts "CHILD"
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
nt = nil
|
nt = nil
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
nt = node.node_type
|
nt = node.node_type
|
||||||
new_nodeset += node.children if nt == :element or nt == :document
|
new_nodeset += node.children if nt == :element or nt == :document
|
||||||
end
|
end
|
||||||
#path_stack[0,(path_stack.size-ps_clone.size)] = []
|
#path_stack[0,(path_stack.size-ps_clone.size)] = []
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :literal
|
when :literal
|
||||||
literal = path_stack.shift
|
literal = path_stack.shift
|
||||||
if literal =~ /^\d+(\.\d+)?$/
|
if literal =~ /^\d+(\.\d+)?$/
|
||||||
return ($1 ? literal.to_f : literal.to_i)
|
return ($1 ? literal.to_f : literal.to_i)
|
||||||
end
|
end
|
||||||
#puts "RETURNING '#{literal}'"
|
#puts "RETURNING '#{literal}'"
|
||||||
return literal
|
return literal
|
||||||
|
|
||||||
when :attribute
|
when :attribute
|
||||||
#puts ":ATTRIBUTE"
|
new_nodeset = []
|
||||||
new_nodeset = []
|
case path_stack.shift
|
||||||
case path_stack.shift
|
when :qname
|
||||||
when :qname
|
prefix = path_stack.shift
|
||||||
prefix = path_stack.shift
|
name = path_stack.shift
|
||||||
name = path_stack.shift
|
for element in nodeset
|
||||||
for element in nodeset
|
if element.node_type == :element
|
||||||
if element.node_type == :element
|
#puts element.name
|
||||||
#puts element.name
|
#puts "looking for attribute #{name} in '#{@namespaces[prefix]}'"
|
||||||
#puts "looking for attribute #{name} in '#{@namespaces[prefix]}'"
|
attr = element.attribute( name, @namespaces[prefix] )
|
||||||
attr = element.attribute( name, @namespaces[prefix] )
|
#puts ":ATTRIBUTE: attr => #{attr}"
|
||||||
#puts ":ATTRIBUTE: attr => #{attr}"
|
new_nodeset << attr if attr
|
||||||
new_nodeset << attr if attr
|
end
|
||||||
end
|
end
|
||||||
end
|
when :any
|
||||||
when :any
|
for element in nodeset
|
||||||
for element in nodeset
|
if element.node_type == :element
|
||||||
if element.node_type == :element
|
attr = element.attributes
|
||||||
attr = element.attributes
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
#puts "RETURNING #{new_nodeset.collect{|n|n.to_s}.inspect}"
|
||||||
#puts "RETURNING #{new_nodeset.collect{|n|n.to_s}.inspect}"
|
return new_nodeset
|
||||||
return new_nodeset
|
|
||||||
|
|
||||||
when :parent
|
when :parent
|
||||||
return internal_parse( path_stack, nodeset.collect{|n| n.parent}.compact )
|
return internal_parse( path_stack, nodeset.collect{|n| n.parent}.compact )
|
||||||
|
|
||||||
when :ancestor
|
when :ancestor
|
||||||
#puts "ANCESTOR"
|
#puts "ANCESTOR"
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
while node.parent
|
while node.parent
|
||||||
node = node.parent
|
node = node.parent
|
||||||
new_nodeset << node unless new_nodeset.include? node
|
new_nodeset << node unless new_nodeset.include? node
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#nodeset = new_nodeset.uniq
|
#nodeset = new_nodeset.uniq
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :ancestor_or_self
|
when :ancestor_or_self
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
if node.node_type == :element
|
if node.node_type == :element
|
||||||
new_nodeset << node
|
new_nodeset << node
|
||||||
while ( node.parent )
|
while ( node.parent )
|
||||||
node = node.parent
|
node = node.parent
|
||||||
new_nodeset << node unless new_nodeset.includes? node
|
new_nodeset << node unless new_nodeset.includes? node
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#nodeset = new_nodeset.uniq
|
#nodeset = new_nodeset.uniq
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :predicate
|
when :predicate
|
||||||
#puts "@"*80
|
#puts "@"*80
|
||||||
#puts "NODESET = #{nodeset.collect{|n|n.to_s}.inspect}"
|
#puts "NODESET = #{nodeset.collect{|n|n.to_s}.inspect}"
|
||||||
predicate = path_stack.shift
|
predicate = path_stack.shift
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
Functions::size = nodeset.size
|
Functions::size = nodeset.size
|
||||||
nodeset.size.times do |index|
|
nodeset.size.times do |index|
|
||||||
node = nodeset[index]
|
node = nodeset[index]
|
||||||
Functions::node = node
|
Functions::node = node
|
||||||
Functions::index = index+1
|
Functions::index = index+1
|
||||||
#puts "Node #{node} and index=#{index+1}"
|
#puts "Node #{node} and index=#{index+1}"
|
||||||
result = Predicate( predicate, node )
|
result = Predicate( predicate, node )
|
||||||
#puts "Predicate returned #{result} (#{result.class}) for #{node.class}"
|
#puts "Predicate returned #{result} (#{result.class}) for #{node.class}"
|
||||||
if result.kind_of? Numeric
|
if result.kind_of? Numeric
|
||||||
#puts "#{result} == #{index} => #{result == index}"
|
#puts "#{result} == #{index} => #{result == index}"
|
||||||
new_nodeset << node if result == (index+1)
|
new_nodeset << node if result == (index+1)
|
||||||
elsif result.instance_of? Array
|
elsif result.instance_of? Array
|
||||||
new_nodeset << node if result.size > 0
|
new_nodeset << node if result.size > 0
|
||||||
else
|
else
|
||||||
new_nodeset << node if result
|
new_nodeset << node if result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#puts "Nodeset after predicate #{predicate.inspect} has #{new_nodeset.size} nodes"
|
#puts "Nodeset after predicate #{predicate.inspect} has #{new_nodeset.size} nodes"
|
||||||
#puts "NODESET: #{new_nodeset.collect{|n|n.to_s}.inspect}"
|
#puts "NODESET: #{new_nodeset.collect{|n|n.to_s}.inspect}"
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :descendant_or_self
|
when :descendant_or_self
|
||||||
rv = descendant_or_self( path_stack, nodeset )
|
rv = descendant_or_self( path_stack, nodeset )
|
||||||
path_stack.clear
|
path_stack.clear
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
when :descendant
|
when :descendant
|
||||||
#puts ":DESCENDANT"
|
#puts ":DESCENDANT"
|
||||||
results = []
|
results = []
|
||||||
nt = nil
|
nt = nil
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
nt = node.node_type
|
nt = node.node_type
|
||||||
results += internal_parse( path_stack.clone.unshift( :descendant_or_self ),
|
results += internal_parse( path_stack.clone.unshift( :descendant_or_self ),
|
||||||
node.children ) if nt == :element or nt == :document
|
node.children ) if nt == :element or nt == :document
|
||||||
end
|
end
|
||||||
return results
|
return results
|
||||||
|
|
||||||
when :following_sibling
|
when :following_sibling
|
||||||
results = []
|
results = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
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 ]
|
||||||
results += internal_parse( path_stack.clone, following_siblings )
|
results += internal_parse( path_stack.clone, following_siblings )
|
||||||
end
|
end
|
||||||
return results
|
return results
|
||||||
|
|
||||||
when :preceding_sibling
|
when :preceding_sibling
|
||||||
results = []
|
results = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
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 ]
|
preceding_siblings = all_siblings[ 0 .. current_index-1 ]
|
||||||
results += internal_parse( path_stack.clone, preceding_siblings )
|
results += internal_parse( path_stack.clone, preceding_siblings )
|
||||||
end
|
end
|
||||||
return results
|
return results
|
||||||
|
|
||||||
when :preceding
|
when :preceding
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
new_nodeset += preceding( node )
|
new_nodeset += preceding( node )
|
||||||
end
|
end
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :following
|
when :following
|
||||||
new_nodeset = []
|
new_nodeset = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
new_nodeset += following( node )
|
new_nodeset += following( node )
|
||||||
end
|
end
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :namespace
|
when :namespace
|
||||||
new_set = []
|
new_set = []
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
new_nodeset << node.namespace if node.node_type == :element or node.node_type == :attribute
|
new_nodeset << node.namespace if node.node_type == :element or node.node_type == :attribute
|
||||||
end
|
end
|
||||||
return new_nodeset
|
return new_nodeset
|
||||||
|
|
||||||
when :variable
|
when :variable
|
||||||
var_name = path_stack.shift
|
var_name = path_stack.shift
|
||||||
return @variables[ var_name ]
|
return @variables[ var_name ]
|
||||||
|
|
||||||
end
|
end
|
||||||
nodeset
|
nodeset
|
||||||
end
|
end
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
# FIXME
|
# FIXME
|
||||||
# The next two methods are BAD MOJO!
|
# The next two methods are BAD MOJO!
|
||||||
# This is my achilles heel. If anybody thinks of a better
|
# This is my achilles heel. If anybody thinks of a better
|
||||||
# way of doing this, be my guest. This really sucks, but
|
# way of doing this, be my guest. This really sucks, but
|
||||||
# it took me three days to get it to work at all.
|
# it took me three days to get it to work at all.
|
||||||
# ########################################################
|
# ########################################################
|
||||||
|
|
||||||
def descendant_or_self( path_stack, nodeset )
|
def descendant_or_self( path_stack, nodeset )
|
||||||
rs = []
|
rs = []
|
||||||
d_o_s( path_stack, nodeset, rs )
|
d_o_s( path_stack, nodeset, rs )
|
||||||
#puts "RS = #{rs.collect{|n|n.to_s}.inspect}"
|
#puts "RS = #{rs.collect{|n|n.to_s}.inspect}"
|
||||||
document_order(rs.flatten.compact)
|
document_order(rs.flatten.compact)
|
||||||
end
|
end
|
||||||
|
|
||||||
def d_o_s( p, ns, r )
|
def d_o_s( p, ns, r )
|
||||||
nt = nil
|
nt = nil
|
||||||
ns.each_index do |i|
|
ns.each_index do |i|
|
||||||
n = ns[i]
|
n = ns[i]
|
||||||
x = match( p.clone, [ n ] )
|
x = match( p.clone, [ n ] )
|
||||||
nt = n.node_type
|
nt = n.node_type
|
||||||
d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0
|
d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0
|
||||||
r.concat(x) if x.size > 0
|
r.concat(x) if x.size > 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Reorders an array of nodes so that they are in document order
|
# Reorders an array of nodes so that they are in document order
|
||||||
|
@ -327,221 +326,231 @@ module REXML
|
||||||
|
|
||||||
def recurse( nodeset, &block )
|
def recurse( nodeset, &block )
|
||||||
for node in nodeset
|
for node in nodeset
|
||||||
yield node
|
yield node
|
||||||
recurse( node, &block ) if node.node_type == :element
|
recurse( node, &block ) if node.node_type == :element
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Given a predicate, a node, and a context, evaluates to true or false.
|
# Given a predicate, a node, and a context, evaluates to true or false.
|
||||||
def Predicate( predicate, node )
|
def Predicate( predicate, node )
|
||||||
predicate = predicate.clone
|
predicate = predicate.clone
|
||||||
#puts "#"*20
|
#puts "#"*20
|
||||||
#puts "Predicate( #{predicate.inspect}, #{node.class} )"
|
#puts "Predicate( #{predicate.inspect}, #{node.class} )"
|
||||||
results = []
|
results = []
|
||||||
case (predicate[0])
|
case (predicate[0])
|
||||||
when :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
|
when :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
|
||||||
eq = predicate.shift
|
eq = predicate.shift
|
||||||
left = Predicate( predicate.shift, node )
|
left = Predicate( predicate.shift, node )
|
||||||
right = Predicate( predicate.shift, node )
|
right = Predicate( predicate.shift, node )
|
||||||
return equality_relational_compare( left, eq, right )
|
#puts "LEFT = #{left.inspect}"
|
||||||
|
#puts "RIGHT = #{right.inspect}"
|
||||||
|
return equality_relational_compare( left, eq, right )
|
||||||
|
|
||||||
when :div, :mod, :mult, :plus, :minus
|
when :div, :mod, :mult, :plus, :minus
|
||||||
op = predicate.shift
|
op = predicate.shift
|
||||||
left = Predicate( predicate.shift, node )
|
left = Predicate( predicate.shift, node )
|
||||||
right = Predicate( predicate.shift, node )
|
right = Predicate( predicate.shift, node )
|
||||||
left = Functions::number( left )
|
#puts "LEFT = #{left.inspect}"
|
||||||
right = Functions::number( right )
|
#puts "RIGHT = #{right.inspect}"
|
||||||
case op
|
left = Functions::number( left )
|
||||||
when :div
|
right = Functions::number( right )
|
||||||
return left.to_f / right.to_f
|
#puts "LEFT = #{left.inspect}"
|
||||||
when :mod
|
#puts "RIGHT = #{right.inspect}"
|
||||||
return left % right
|
case op
|
||||||
when :mult
|
when :div
|
||||||
return left * right
|
return left.to_f / right.to_f
|
||||||
when :plus
|
when :mod
|
||||||
return left + right
|
return left % right
|
||||||
when :minus
|
when :mult
|
||||||
return left - right
|
return left * right
|
||||||
end
|
when :plus
|
||||||
|
return left + right
|
||||||
|
when :minus
|
||||||
|
return left - right
|
||||||
|
end
|
||||||
|
|
||||||
when :union
|
when :union
|
||||||
predicate.shift
|
predicate.shift
|
||||||
left = Predicate( predicate.shift, node )
|
left = Predicate( predicate.shift, node )
|
||||||
right = Predicate( predicate.shift, node )
|
right = Predicate( predicate.shift, node )
|
||||||
return (left | right)
|
return (left | right)
|
||||||
|
|
||||||
when :neg
|
when :neg
|
||||||
predicate.shift
|
predicate.shift
|
||||||
operand = Functions::number(Predicate( predicate, node ))
|
operand = Functions::number(Predicate( predicate, node ))
|
||||||
return -operand
|
return -operand
|
||||||
|
|
||||||
when :not
|
when :not
|
||||||
predicate.shift
|
predicate.shift
|
||||||
return !Predicate( predicate.shift, node )
|
return !Predicate( predicate.shift, node )
|
||||||
|
|
||||||
when :function
|
when :function
|
||||||
predicate.shift
|
predicate.shift
|
||||||
func_name = predicate.shift.tr('-', '_')
|
func_name = predicate.shift.tr('-', '_')
|
||||||
arguments = predicate.shift
|
arguments = predicate.shift
|
||||||
#puts "\nFUNCTION: #{func_name}"
|
#puts "\nFUNCTION: #{func_name}"
|
||||||
#puts "ARGUMENTS: #{arguments.inspect} #{node.to_s}"
|
#puts "ARGUMENTS: #{arguments.inspect} #{node.to_s}"
|
||||||
args = arguments.collect { |arg| Predicate( arg, node ) }
|
args = arguments.collect { |arg| Predicate( arg, node ) }
|
||||||
#puts "FUNCTION: #{func_name}( #{args.collect{|n|n.to_s}.inspect} )"
|
#puts "FUNCTION: #{func_name}( #{args.collect{|n|n.to_s}.inspect} )"
|
||||||
result = Functions.send( func_name, *args )
|
result = Functions.send( func_name, *args )
|
||||||
#puts "RESULTS: #{result.inspect}"
|
#puts "RESULTS: #{result.inspect}"
|
||||||
return result
|
return result
|
||||||
|
|
||||||
else
|
else
|
||||||
return match( predicate, [ node ] )
|
return match( predicate, [ node ] )
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Builds a nodeset of all of the following nodes of the supplied node,
|
# Builds a nodeset of all of the following nodes of the supplied node,
|
||||||
# in document order
|
# in document order
|
||||||
def following( node )
|
def following( node )
|
||||||
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 ]
|
||||||
following = []
|
following = []
|
||||||
recurse( following_siblings ) { |node| following << node }
|
recurse( following_siblings ) { |node| following << node }
|
||||||
following.shift
|
following.shift
|
||||||
#puts "following is returning #{puta following}"
|
#puts "following is returning #{puta following}"
|
||||||
following
|
following
|
||||||
end
|
end
|
||||||
|
|
||||||
# Builds a nodeset of all of the preceding nodes of the supplied node,
|
# Builds a nodeset of all of the preceding nodes of the supplied node,
|
||||||
# in reverse document order
|
# in reverse document order
|
||||||
def preceding( node )
|
def preceding( node )
|
||||||
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 ]
|
preceding_siblings = all_siblings[ 0 .. current_index-1 ]
|
||||||
|
|
||||||
preceding_siblings.reverse!
|
preceding_siblings.reverse!
|
||||||
preceding = []
|
preceding = []
|
||||||
recurse( preceding_siblings ) { |node| preceding << node }
|
recurse( preceding_siblings ) { |node| preceding << node }
|
||||||
preceding.reverse
|
preceding.reverse
|
||||||
end
|
end
|
||||||
|
|
||||||
def equality_relational_compare( set1, op, set2 )
|
def equality_relational_compare( set1, op, set2 )
|
||||||
#puts "EQ_REL_COMP: #{set1.to_s}, #{op}, #{set2.to_s}"
|
#puts "EQ_REL_COMP: #{set1.to_s}, #{op}, #{set2.to_s}"
|
||||||
#puts "#{set1.class.name} #{op} #{set2.class.name}"
|
#puts "#{set1.class.name} #{op} #{set2.class.name}"
|
||||||
if set1.kind_of? Array and set2.kind_of? Array
|
if set1.kind_of? Array and set2.kind_of? Array
|
||||||
#puts "#{set1.size} & #{set2.size}"
|
#puts "#{set1.size} & #{set2.size}"
|
||||||
if set1.size == 1 and set2.size == 1
|
if set1.size == 1 and set2.size == 1
|
||||||
set1 = set1[0]
|
set1 = set1[0]
|
||||||
set2 = set2[0]
|
set2 = set2[0]
|
||||||
elsif set1.size == 0 or set2.size == 0
|
elsif set1.size == 0 or set2.size == 0
|
||||||
nd = set1.size==0 ? set2 : set1
|
nd = set1.size==0 ? set2 : set1
|
||||||
nd.each { |il| return true if compare( il, op, nil ) }
|
nd.each { |il| return true if compare( il, op, nil ) }
|
||||||
else
|
else
|
||||||
set1.each do |i1|
|
set1.each do |i1|
|
||||||
i1 = i1.to_s
|
i1 = i1.to_s
|
||||||
set2.each do |i2|
|
set2.each do |i2|
|
||||||
i2 = i2.to_s
|
i2 = i2.to_s
|
||||||
return true if compare( i1, op, i2 )
|
return true if compare( i1, op, i2 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#puts "COMPARING VALUES"
|
#puts "COMPARING VALUES"
|
||||||
# If one is nodeset and other is number, compare number to each item
|
# If one is nodeset and other is number, compare number to each item
|
||||||
# in nodeset s.t. number op number(string(item))
|
# in nodeset s.t. number op number(string(item))
|
||||||
# If one is nodeset and other is string, compare string to each item
|
# If one is nodeset and other is string, compare string to each item
|
||||||
# in nodeset s.t. string op string(item)
|
# in nodeset s.t. string op string(item)
|
||||||
# If one is nodeset and other is boolean, compare boolean to each item
|
# If one is nodeset and other is boolean, compare boolean to each item
|
||||||
# in nodeset s.t. boolean op boolean(item)
|
# in nodeset s.t. boolean op boolean(item)
|
||||||
if set1.kind_of? Array or set2.kind_of? Array
|
if set1.kind_of? Array or set2.kind_of? Array
|
||||||
#puts "ISA ARRAY"
|
#puts "ISA ARRAY"
|
||||||
if set1.kind_of? Array
|
if set1.kind_of? Array
|
||||||
a = set1
|
a = set1
|
||||||
b = set2.to_s
|
b = set2.to_s
|
||||||
else
|
else
|
||||||
a = set2
|
a = set2
|
||||||
b = set1.to_s
|
b = set1.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
case b
|
case b
|
||||||
when 'true', 'false'
|
when 'true', 'false'
|
||||||
b = Functions::boolean( b )
|
b = Functions::boolean( b )
|
||||||
for v in a
|
for v in a
|
||||||
v = Functions::boolean(v)
|
v = Functions::boolean(v)
|
||||||
return true if compare( v, op, b )
|
return true if compare( v, op, b )
|
||||||
end
|
end
|
||||||
when /^\d+(\.\d+)?$/
|
when /^\d+(\.\d+)?$/
|
||||||
b = Functions::number( b )
|
b = Functions::number( b )
|
||||||
for v in a
|
#puts "B = #{b.inspect}"
|
||||||
v = Functions::number(v)
|
for v in a
|
||||||
return true if compare( v, op, b )
|
#puts "v = #{v.inspect}"
|
||||||
end
|
v = Functions::number(v)
|
||||||
else
|
#puts "v = #{v.inspect}"
|
||||||
b = Functions::string( b )
|
#puts compare(v,op,b)
|
||||||
for v in a
|
return true if compare( v, op, b )
|
||||||
v = Functions::string(v)
|
end
|
||||||
return true if compare( v, op, b )
|
else
|
||||||
end
|
b = Functions::string( b )
|
||||||
end
|
for v in a
|
||||||
else
|
v = Functions::string(v)
|
||||||
# If neither is nodeset,
|
return true if compare( v, op, b )
|
||||||
# If op is = or !=
|
end
|
||||||
# If either boolean, convert to boolean
|
end
|
||||||
# If either number, convert to number
|
else
|
||||||
# Else, convert to string
|
# If neither is nodeset,
|
||||||
# Else
|
# If op is = or !=
|
||||||
# Convert both to numbers and compare
|
# If either boolean, convert to boolean
|
||||||
s1 = set1.to_s
|
# If either number, convert to number
|
||||||
s2 = set2.to_s
|
# Else, convert to string
|
||||||
#puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}"
|
# Else
|
||||||
if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false'
|
# Convert both to numbers and compare
|
||||||
#puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}"
|
s1 = set1.to_s
|
||||||
#puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}"
|
s2 = set2.to_s
|
||||||
set1 = Functions::boolean( set1 )
|
#puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}"
|
||||||
set2 = Functions::boolean( set2 )
|
if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false'
|
||||||
else
|
#puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}"
|
||||||
if op == :eq or op == :neq
|
#puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}"
|
||||||
if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/
|
set1 = Functions::boolean( set1 )
|
||||||
set1 = Functions::number( s1 )
|
set2 = Functions::boolean( set2 )
|
||||||
set2 = Functions::number( s2 )
|
else
|
||||||
else
|
if op == :eq or op == :neq
|
||||||
set1 = Functions::string( set1 )
|
if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/
|
||||||
set2 = Functions::string( set2 )
|
set1 = Functions::number( s1 )
|
||||||
end
|
set2 = Functions::number( s2 )
|
||||||
else
|
else
|
||||||
set1 = Functions::number( set1 )
|
set1 = Functions::string( set1 )
|
||||||
set2 = Functions::number( set2 )
|
set2 = Functions::string( set2 )
|
||||||
end
|
end
|
||||||
end
|
else
|
||||||
#puts "EQ_REL_COMP: #{set1} #{op} #{set2}"
|
set1 = Functions::number( set1 )
|
||||||
|
set2 = Functions::number( set2 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
#puts "EQ_REL_COMP: #{set1} #{op} #{set2}"
|
||||||
#puts ">>> #{compare( set1, op, set2 )}"
|
#puts ">>> #{compare( set1, op, set2 )}"
|
||||||
return compare( set1, op, set2 )
|
return compare( set1, op, set2 )
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare a, op, b
|
def compare a, op, b
|
||||||
#puts "COMPARE #{a.to_s} #{op} #{b.to_s}"
|
#puts "COMPARE #{a.to_s} #{op} #{b.to_s}"
|
||||||
case op
|
case op
|
||||||
when :eq
|
when :eq
|
||||||
a == b
|
a == b
|
||||||
when :neq
|
when :neq
|
||||||
a != b
|
a != b
|
||||||
when :lt
|
when :lt
|
||||||
a < b
|
a < b
|
||||||
when :lteq
|
when :lteq
|
||||||
a <= b
|
a <= b
|
||||||
when :gt
|
when :gt
|
||||||
a > b
|
a > b
|
||||||
when :gteq
|
when :gteq
|
||||||
a >= b
|
a >= b
|
||||||
when :and
|
when :and
|
||||||
a and b
|
a and b
|
||||||
when :or
|
when :or
|
||||||
a or b
|
a or b
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue