mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
rexml: upgrade to 3.1.8
See https://github.com/ruby/rexml/blob/master/NEWS.md for change summary. Changes for spec/ has been reported: https://github.com/ruby/spec/pull/639 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66458 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0b38221d4e
commit
0d1abb904e
26 changed files with 566 additions and 197 deletions
NEWS
lib/rexml
doctype.rb
formatters
functions.rbinstruction.rbnamespace.rbparsers
rexml.gemspecrexml.rbsource.rbtext.rbxmldecl.rbspec/ruby/library/rexml/attribute
test/rexml
3
NEWS
3
NEWS
|
@ -453,6 +453,9 @@ sufficient information, see the ChangeLog file or Redmine
|
||||||
|
|
||||||
[REXML]
|
[REXML]
|
||||||
|
|
||||||
|
* Upgrade to REXML 3.1.8
|
||||||
|
https://github.com/ruby/rexml/blob/master/NEWS.md
|
||||||
|
|
||||||
[Improved some XPath implementations]
|
[Improved some XPath implementations]
|
||||||
|
|
||||||
* <code>concat()</code> function: Stringify all arguments before concatenating
|
* <code>concat()</code> function: Stringify all arguments before concatenating
|
||||||
|
|
|
@ -108,13 +108,19 @@ module REXML
|
||||||
# Ignored
|
# Ignored
|
||||||
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
|
f = REXML::Formatters::Default.new
|
||||||
|
c = context
|
||||||
|
if c and c[:prologue_quote] == :apostrophe
|
||||||
|
quote = "'"
|
||||||
|
else
|
||||||
|
quote = "\""
|
||||||
|
end
|
||||||
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.inspect}" if @long_name
|
output << " #{quote}#{@long_name}#{quote}" if @long_name
|
||||||
output << " #{@uri.inspect}" if @uri
|
output << " #{quote}#{@uri}#{quote}" if @uri
|
||||||
unless @children.empty?
|
unless @children.empty?
|
||||||
output << ' ['
|
output << ' ['
|
||||||
@children.each { |child|
|
@children.each { |child|
|
||||||
|
@ -127,7 +133,11 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
def context
|
def context
|
||||||
@parent.context
|
if @parent
|
||||||
|
@parent.context
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def entity( name )
|
def entity( name )
|
||||||
|
@ -249,9 +259,16 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
c = nil
|
||||||
|
c = parent.context if parent
|
||||||
|
if c and c[:prologue_quote] == :apostrophe
|
||||||
|
quote = "'"
|
||||||
|
else
|
||||||
|
quote = "\""
|
||||||
|
end
|
||||||
notation = "<!NOTATION #{@name} #{@middle}"
|
notation = "<!NOTATION #{@name} #{@middle}"
|
||||||
notation << " #{@public.inspect}" if @public
|
notation << " #{quote}#{@public}#{quote}" if @public
|
||||||
notation << " #{@system.inspect}" if @system
|
notation << " #{quote}#{@system}#{quote}" if @system
|
||||||
notation << ">"
|
notation << ">"
|
||||||
notation
|
notation
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
module REXML
|
module REXML
|
||||||
module Formatters
|
module Formatters
|
||||||
class Default
|
class Default
|
||||||
|
@ -101,11 +102,14 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_instruction( node, output )
|
def write_instruction( node, output )
|
||||||
output << Instruction::START.sub(/\\/u, '')
|
output << Instruction::START
|
||||||
output << node.target
|
output << node.target
|
||||||
output << ' '
|
content = node.content
|
||||||
output << node.content
|
if content
|
||||||
output << Instruction::STOP.sub(/\\/u, '')
|
output << ' '
|
||||||
|
output << content
|
||||||
|
end
|
||||||
|
output << Instruction::STOP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -423,7 +423,7 @@ module REXML
|
||||||
number = number(number)
|
number = number(number)
|
||||||
begin
|
begin
|
||||||
neg = number.negative?
|
neg = number.negative?
|
||||||
number = number.abs.round(half: :up)
|
number = number.abs.round
|
||||||
neg ? -number : number
|
neg ? -number : number
|
||||||
rescue FloatDomainError
|
rescue FloatDomainError
|
||||||
number
|
number
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
require_relative "child"
|
require_relative "child"
|
||||||
require_relative "source"
|
require_relative "source"
|
||||||
|
|
||||||
|
@ -6,8 +7,8 @@ module REXML
|
||||||
# Represents an XML Instruction; IE, <? ... ?>
|
# Represents an XML Instruction; IE, <? ... ?>
|
||||||
# TODO: Add parent arg (3rd arg) to constructor
|
# TODO: Add parent arg (3rd arg) to constructor
|
||||||
class Instruction < Child
|
class Instruction < Child
|
||||||
START = '<\?'
|
START = "<?"
|
||||||
STOP = '\?>'
|
STOP = "?>"
|
||||||
|
|
||||||
# target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
|
# target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
|
||||||
# content is everything else.
|
# content is everything else.
|
||||||
|
@ -17,20 +18,25 @@ module REXML
|
||||||
# @param target can be one of a number of things. If String, then
|
# @param target can be one of a number of things. If String, then
|
||||||
# the target of this instruction is set to this. If an Instruction,
|
# the target of this instruction is set to this. If an Instruction,
|
||||||
# then the Instruction is shallowly cloned (target and content are
|
# then the Instruction is shallowly cloned (target and content are
|
||||||
# copied). If a Source, then the source is scanned and parsed for
|
# copied).
|
||||||
# an Instruction declaration.
|
|
||||||
# @param content Must be either a String, or a Parent. Can only
|
# @param content Must be either a String, or a Parent. Can only
|
||||||
# be a Parent if the target argument is a Source. Otherwise, this
|
# be a Parent if the target argument is a Source. Otherwise, this
|
||||||
# String is set as the content of this instruction.
|
# String is set as the content of this instruction.
|
||||||
def initialize(target, content=nil)
|
def initialize(target, content=nil)
|
||||||
if target.kind_of? String
|
case target
|
||||||
|
when String
|
||||||
super()
|
super()
|
||||||
@target = target
|
@target = target
|
||||||
@content = content
|
@content = content
|
||||||
elsif target.kind_of? Instruction
|
when Instruction
|
||||||
super(content)
|
super(content)
|
||||||
@target = target.target
|
@target = target.target
|
||||||
@content = target.content
|
@content = target.content
|
||||||
|
else
|
||||||
|
message =
|
||||||
|
"processing instruction target must be String or REXML::Instruction: "
|
||||||
|
message << "<#{target.inspect}>"
|
||||||
|
raise ArgumentError, message
|
||||||
end
|
end
|
||||||
@content.strip! if @content
|
@content.strip! if @content
|
||||||
end
|
end
|
||||||
|
@ -45,11 +51,13 @@ module REXML
|
||||||
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", uplevel: 1)
|
Kernel.warn( "#{self.class.name}.write is deprecated", uplevel: 1)
|
||||||
indent(writer, indent)
|
indent(writer, indent)
|
||||||
writer << START.sub(/\\/u, '')
|
writer << START
|
||||||
writer << @target
|
writer << @target
|
||||||
writer << ' '
|
if @content
|
||||||
writer << @content
|
writer << ' '
|
||||||
writer << STOP.sub(/\\/u, '')
|
writer << @content
|
||||||
|
end
|
||||||
|
writer << STOP
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return true if other is an Instruction, and the content and target
|
# @return true if other is an Instruction, and the content and target
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
require_relative 'xmltokens'
|
require_relative 'xmltokens'
|
||||||
|
|
||||||
module REXML
|
module REXML
|
||||||
|
@ -14,14 +15,24 @@ module REXML
|
||||||
# Sets the name and the expanded name
|
# Sets the name and the expanded name
|
||||||
def name=( name )
|
def name=( name )
|
||||||
@expanded_name = name
|
@expanded_name = name
|
||||||
name =~ NAMESPLIT
|
case name
|
||||||
if $1
|
when NAMESPLIT
|
||||||
@prefix = $1
|
if $1
|
||||||
|
@prefix = $1
|
||||||
|
else
|
||||||
|
@prefix = ""
|
||||||
|
@namespace = ""
|
||||||
|
end
|
||||||
|
@name = $2
|
||||||
|
when ""
|
||||||
|
@prefix = nil
|
||||||
|
@namespace = nil
|
||||||
|
@name = nil
|
||||||
else
|
else
|
||||||
@prefix = ""
|
message = "name must be \#{PREFIX}:\#{LOCAL_NAME} or \#{LOCAL_NAME}: "
|
||||||
@namespace = ""
|
message += "<#{name.inspect}>"
|
||||||
|
raise ArgumentError, message
|
||||||
end
|
end
|
||||||
@name = $2
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Compares names optionally WITH namespaces
|
# Compares names optionally WITH namespaces
|
||||||
|
|
|
@ -3,6 +3,7 @@ require_relative '../parseexception'
|
||||||
require_relative '../undefinednamespaceexception'
|
require_relative '../undefinednamespaceexception'
|
||||||
require_relative '../source'
|
require_relative '../source'
|
||||||
require 'set'
|
require 'set'
|
||||||
|
require "strscan"
|
||||||
|
|
||||||
module REXML
|
module REXML
|
||||||
module Parsers
|
module Parsers
|
||||||
|
@ -32,9 +33,9 @@ module REXML
|
||||||
COMBININGCHAR = '' # TODO
|
COMBININGCHAR = '' # TODO
|
||||||
EXTENDER = '' # TODO
|
EXTENDER = '' # TODO
|
||||||
|
|
||||||
NCNAME_STR= "[#{LETTER}_:][-[:alnum:]._:#{COMBININGCHAR}#{EXTENDER}]*"
|
NCNAME_STR= "[#{LETTER}_][-[:alnum:]._#{COMBININGCHAR}#{EXTENDER}]*"
|
||||||
NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
|
QNAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
|
||||||
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
|
QNAME = /(#{QNAME_STR})/
|
||||||
|
|
||||||
NAMECHAR = '[\-\w\.:]'
|
NAMECHAR = '[\-\w\.:]'
|
||||||
NAME = "([\\w:]#{NAMECHAR}*)"
|
NAME = "([\\w:]#{NAMECHAR}*)"
|
||||||
|
@ -46,7 +47,7 @@ module REXML
|
||||||
DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
|
DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
|
||||||
DOCTYPE_END = /\A\s*\]\s*>/um
|
DOCTYPE_END = /\A\s*\]\s*>/um
|
||||||
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
|
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
|
||||||
ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um
|
ATTRIBUTE_PATTERN = /\s*(#{QNAME_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
|
||||||
|
@ -55,9 +56,9 @@ module REXML
|
||||||
XMLDECL_START = /\A<\?xml\s/u;
|
XMLDECL_START = /\A<\?xml\s/u;
|
||||||
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
|
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
|
||||||
INSTRUCTION_START = /\A<\?/u
|
INSTRUCTION_START = /\A<\?/u
|
||||||
INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um
|
INSTRUCTION_PATTERN = /<\?#{NAME}(\s+.*?)?\?>/um
|
||||||
TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um
|
TAG_MATCH = /^<((?>#{QNAME_STR}))/um
|
||||||
CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um
|
CLOSE_MATCH = /^\s*<\/(#{QNAME_STR})\s*>/um
|
||||||
|
|
||||||
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
|
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
|
||||||
ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
|
ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
|
||||||
|
@ -107,13 +108,6 @@ 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
|
||||||
@listeners = []
|
@listeners = []
|
||||||
|
@ -224,7 +218,7 @@ module REXML
|
||||||
standalone = standalone[1] unless standalone.nil?
|
standalone = standalone[1] unless standalone.nil?
|
||||||
return [ :xmldecl, version, encoding, standalone ]
|
return [ :xmldecl, version, encoding, standalone ]
|
||||||
when INSTRUCTION_START
|
when INSTRUCTION_START
|
||||||
return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ]
|
return process_instruction
|
||||||
when DOCTYPE_START
|
when DOCTYPE_START
|
||||||
md = @source.match( DOCTYPE_PATTERN, true )
|
md = @source.match( DOCTYPE_PATTERN, true )
|
||||||
@nsstack.unshift(curr_ns=Set.new)
|
@nsstack.unshift(curr_ns=Set.new)
|
||||||
|
@ -336,11 +330,12 @@ module REXML
|
||||||
if @source.buffer[1] == ?/
|
if @source.buffer[1] == ?/
|
||||||
@nsstack.shift
|
@nsstack.shift
|
||||||
last_tag = @tags.pop
|
last_tag = @tags.pop
|
||||||
#md = @source.match_to_consume( '>', CLOSE_MATCH)
|
|
||||||
md = @source.match( CLOSE_MATCH, true )
|
md = @source.match( CLOSE_MATCH, true )
|
||||||
raise REXML::ParseException.new( "Missing end tag for "+
|
if md.nil? or last_tag != md[1]
|
||||||
"'#{last_tag}' (got \"#{md[1]}\")",
|
message = "Missing end tag for '#{last_tag}'"
|
||||||
@source) unless last_tag == md[1]
|
message << " (got '#{md[1]}')" if md
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
return [ :end_element, last_tag ]
|
return [ :end_element, last_tag ]
|
||||||
elsif @source.buffer[1] == ?!
|
elsif @source.buffer[1] == ?!
|
||||||
md = @source.match(/\A(\s*[^>]*>)/um)
|
md = @source.match(/\A(\s*[^>]*>)/um)
|
||||||
|
@ -362,52 +357,17 @@ module REXML
|
||||||
raise REXML::ParseException.new( "Declarations can only occur "+
|
raise REXML::ParseException.new( "Declarations can only occur "+
|
||||||
"in the doctype declaration.", @source)
|
"in the doctype declaration.", @source)
|
||||||
elsif @source.buffer[1] == ??
|
elsif @source.buffer[1] == ??
|
||||||
md = @source.match( INSTRUCTION_PATTERN, true )
|
return process_instruction
|
||||||
return [ :processing_instruction, md[1], md[2] ] if md
|
|
||||||
raise REXML::ParseException.new( "Bad instruction declaration",
|
|
||||||
@source)
|
|
||||||
else
|
else
|
||||||
# Get the next tag
|
# Get the next tag
|
||||||
md = @source.match(TAG_MATCH, true)
|
md = @source.match(TAG_MATCH, true)
|
||||||
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)
|
raise REXML::ParseException.new("malformed XML: missing tag start", @source)
|
||||||
end
|
end
|
||||||
attributes = {}
|
|
||||||
prefixes = Set.new
|
prefixes = Set.new
|
||||||
prefixes << md[2] if md[2]
|
prefixes << md[2] if md[2]
|
||||||
@nsstack.unshift(curr_ns=Set.new)
|
@nsstack.unshift(curr_ns=Set.new)
|
||||||
if md[4].size > 0
|
attributes, closed = parse_attributes(prefixes, curr_ns)
|
||||||
attrs = md[4].scan( ATTRIBUTE_PATTERN )
|
|
||||||
raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0
|
|
||||||
attrs.each do |attr_name, prefix, local_part, quote, value|
|
|
||||||
if prefix == "xmlns"
|
|
||||||
if local_part == "xml"
|
|
||||||
if value != "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 local_part == "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 << local_part
|
|
||||||
elsif prefix
|
|
||||||
prefixes << prefix unless prefix == "xml"
|
|
||||||
end
|
|
||||||
|
|
||||||
if attributes.has_key?(attr_name)
|
|
||||||
msg = "Duplicate attribute #{attr_name.inspect}"
|
|
||||||
raise REXML::ParseException.new(msg, @source, self)
|
|
||||||
end
|
|
||||||
|
|
||||||
attributes[attr_name] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Verify that all of the prefixes have been defined
|
# Verify that all of the prefixes have been defined
|
||||||
for prefix in prefixes
|
for prefix in prefixes
|
||||||
unless @nsstack.find{|k| k.member?(prefix)}
|
unless @nsstack.find{|k| k.member?(prefix)}
|
||||||
|
@ -415,7 +375,7 @@ module REXML
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if md[6]
|
if closed
|
||||||
@closed = md[1]
|
@closed = md[1]
|
||||||
@nsstack.shift
|
@nsstack.shift
|
||||||
else
|
else
|
||||||
|
@ -438,7 +398,7 @@ module REXML
|
||||||
raise
|
raise
|
||||||
rescue REXML::ParseException
|
rescue REXML::ParseException
|
||||||
raise
|
raise
|
||||||
rescue Exception, NameError => error
|
rescue => error
|
||||||
raise REXML::ParseException.new( "Exception parsing",
|
raise REXML::ParseException.new( "Exception parsing",
|
||||||
@source, self, (error ? error : $!) )
|
@source, self, (error ? error : $!) )
|
||||||
end
|
end
|
||||||
|
@ -508,6 +468,99 @@ module REXML
|
||||||
return false if /\AUTF-16\z/i =~ xml_declaration_encoding
|
return false if /\AUTF-16\z/i =~ xml_declaration_encoding
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_instruction
|
||||||
|
match_data = @source.match(INSTRUCTION_PATTERN, true)
|
||||||
|
unless match_data
|
||||||
|
message = "Invalid processing instruction node"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
[:processing_instruction, match_data[1], match_data[2]]
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_attributes(prefixes, curr_ns)
|
||||||
|
attributes = {}
|
||||||
|
closed = false
|
||||||
|
match_data = @source.match(/^(.*?)(\/)?>/um, true)
|
||||||
|
if match_data.nil?
|
||||||
|
message = "Start tag isn't ended"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
|
||||||
|
raw_attributes = match_data[1]
|
||||||
|
closed = !match_data[2].nil?
|
||||||
|
return attributes, closed if raw_attributes.nil?
|
||||||
|
return attributes, closed if raw_attributes.empty?
|
||||||
|
|
||||||
|
scanner = StringScanner.new(raw_attributes)
|
||||||
|
until scanner.eos?
|
||||||
|
if scanner.scan(/\s+/)
|
||||||
|
break if scanner.eos?
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = scanner.pos
|
||||||
|
loop do
|
||||||
|
break if scanner.scan(ATTRIBUTE_PATTERN)
|
||||||
|
unless scanner.scan(QNAME)
|
||||||
|
message = "Invalid attribute name: <#{scanner.rest}>"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
name = scanner[0]
|
||||||
|
unless scanner.scan(/\s*=\s*/um)
|
||||||
|
message = "Missing attribute equal: <#{name}>"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
quote = scanner.scan(/['"]/)
|
||||||
|
unless quote
|
||||||
|
message = "Missing attribute value start quote: <#{name}>"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
unless scanner.scan(/.*#{Regexp.escape(quote)}/um)
|
||||||
|
match_data = @source.match(/^(.*?)(\/)?>/um, true)
|
||||||
|
if match_data
|
||||||
|
scanner << "/" if closed
|
||||||
|
scanner << ">"
|
||||||
|
scanner << match_data[1]
|
||||||
|
scanner.pos = pos
|
||||||
|
closed = !match_data[2].nil?
|
||||||
|
next
|
||||||
|
end
|
||||||
|
message =
|
||||||
|
"Missing attribute value end quote: <#{name}>: <#{quote}>"
|
||||||
|
raise REXML::ParseException.new(message, @source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
name = scanner[1]
|
||||||
|
prefix = scanner[2]
|
||||||
|
local_part = scanner[3]
|
||||||
|
# quote = scanner[4]
|
||||||
|
value = scanner[5]
|
||||||
|
if prefix == "xmlns"
|
||||||
|
if local_part == "xml"
|
||||||
|
if value != "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 local_part == "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 << local_part
|
||||||
|
elsif prefix
|
||||||
|
prefixes << prefix unless prefix == "xml"
|
||||||
|
end
|
||||||
|
|
||||||
|
if attributes.has_key?(name)
|
||||||
|
msg = "Duplicate attribute #{name.inspect}"
|
||||||
|
raise REXML::ParseException.new(msg, @source, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes[name] = value
|
||||||
|
end
|
||||||
|
return attributes, closed
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,23 +16,65 @@ Gem::Specification.new do |spec|
|
||||||
spec.homepage = "https://github.com/ruby/rexml"
|
spec.homepage = "https://github.com/ruby/rexml"
|
||||||
spec.license = "BSD-2-Clause"
|
spec.license = "BSD-2-Clause"
|
||||||
|
|
||||||
spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile",
|
spec.files = [
|
||||||
"bin/console", "bin/setup", "lib/rexml/attlistdecl.rb", "lib/rexml/attribute.rb", "lib/rexml/cdata.rb",
|
".gitignore",
|
||||||
"lib/rexml/child.rb", "lib/rexml/comment.rb", "lib/rexml/doctype.rb", "lib/rexml/document.rb",
|
".travis.yml",
|
||||||
"lib/rexml/dtd/attlistdecl.rb", "lib/rexml/dtd/dtd.rb", "lib/rexml/dtd/elementdecl.rb",
|
"Gemfile",
|
||||||
"lib/rexml/dtd/entitydecl.rb", "lib/rexml/dtd/notationdecl.rb", "lib/rexml/element.rb",
|
"LICENSE.txt",
|
||||||
"lib/rexml/encoding.rb", "lib/rexml/entity.rb", "lib/rexml/formatters/default.rb",
|
"README.md",
|
||||||
"lib/rexml/formatters/pretty.rb", "lib/rexml/formatters/transitive.rb", "lib/rexml/functions.rb",
|
"Rakefile",
|
||||||
"lib/rexml/instruction.rb", "lib/rexml/light/node.rb", "lib/rexml/namespace.rb", "lib/rexml/node.rb",
|
"lib/rexml/attlistdecl.rb",
|
||||||
"lib/rexml/output.rb", "lib/rexml/parent.rb", "lib/rexml/parseexception.rb", "lib/rexml/parsers/baseparser.rb",
|
"lib/rexml/attribute.rb",
|
||||||
"lib/rexml/parsers/lightparser.rb", "lib/rexml/parsers/pullparser.rb", "lib/rexml/parsers/sax2parser.rb",
|
"lib/rexml/cdata.rb",
|
||||||
"lib/rexml/parsers/streamparser.rb", "lib/rexml/parsers/treeparser.rb",
|
"lib/rexml/child.rb",
|
||||||
"lib/rexml/parsers/ultralightparser.rb", "lib/rexml/parsers/xpathparser.rb", "lib/rexml/quickpath.rb",
|
"lib/rexml/comment.rb",
|
||||||
"lib/rexml/rexml.rb", "lib/rexml/sax2listener.rb", "lib/rexml/security.rb", "lib/rexml/source.rb",
|
"lib/rexml/doctype.rb",
|
||||||
"lib/rexml/streamlistener.rb", "lib/rexml/syncenumerator.rb", "lib/rexml/text.rb",
|
"lib/rexml/document.rb",
|
||||||
"lib/rexml/undefinednamespaceexception.rb", "lib/rexml/validation/relaxng.rb",
|
"lib/rexml/dtd/attlistdecl.rb",
|
||||||
"lib/rexml/validation/validation.rb", "lib/rexml/validation/validationexception.rb", "lib/rexml/xmldecl.rb",
|
"lib/rexml/dtd/dtd.rb",
|
||||||
"lib/rexml/xmltokens.rb", "lib/rexml/xpath.rb", "lib/rexml/xpath_parser.rb", "rexml.gemspec"]
|
"lib/rexml/dtd/elementdecl.rb",
|
||||||
|
"lib/rexml/dtd/entitydecl.rb",
|
||||||
|
"lib/rexml/dtd/notationdecl.rb",
|
||||||
|
"lib/rexml/element.rb",
|
||||||
|
"lib/rexml/encoding.rb",
|
||||||
|
"lib/rexml/entity.rb",
|
||||||
|
"lib/rexml/formatters/default.rb",
|
||||||
|
"lib/rexml/formatters/pretty.rb",
|
||||||
|
"lib/rexml/formatters/transitive.rb",
|
||||||
|
"lib/rexml/functions.rb",
|
||||||
|
"lib/rexml/instruction.rb",
|
||||||
|
"lib/rexml/light/node.rb",
|
||||||
|
"lib/rexml/namespace.rb",
|
||||||
|
"lib/rexml/node.rb",
|
||||||
|
"lib/rexml/output.rb",
|
||||||
|
"lib/rexml/parent.rb",
|
||||||
|
"lib/rexml/parseexception.rb",
|
||||||
|
"lib/rexml/parsers/baseparser.rb",
|
||||||
|
"lib/rexml/parsers/lightparser.rb",
|
||||||
|
"lib/rexml/parsers/pullparser.rb",
|
||||||
|
"lib/rexml/parsers/sax2parser.rb",
|
||||||
|
"lib/rexml/parsers/streamparser.rb",
|
||||||
|
"lib/rexml/parsers/treeparser.rb",
|
||||||
|
"lib/rexml/parsers/ultralightparser.rb",
|
||||||
|
"lib/rexml/parsers/xpathparser.rb",
|
||||||
|
"lib/rexml/quickpath.rb",
|
||||||
|
"lib/rexml/rexml.rb",
|
||||||
|
"lib/rexml/sax2listener.rb",
|
||||||
|
"lib/rexml/security.rb",
|
||||||
|
"lib/rexml/source.rb",
|
||||||
|
"lib/rexml/streamlistener.rb",
|
||||||
|
"lib/rexml/syncenumerator.rb",
|
||||||
|
"lib/rexml/text.rb",
|
||||||
|
"lib/rexml/undefinednamespaceexception.rb",
|
||||||
|
"lib/rexml/validation/relaxng.rb",
|
||||||
|
"lib/rexml/validation/validation.rb",
|
||||||
|
"lib/rexml/validation/validationexception.rb",
|
||||||
|
"lib/rexml/xmldecl.rb",
|
||||||
|
"lib/rexml/xmltokens.rb",
|
||||||
|
"lib/rexml/xpath.rb",
|
||||||
|
"lib/rexml/xpath_parser.rb",
|
||||||
|
"rexml.gemspec",
|
||||||
|
]
|
||||||
spec.bindir = "exe"
|
spec.bindir = "exe"
|
||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
spec.require_paths = ["lib"]
|
spec.require_paths = ["lib"]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
# 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.
|
||||||
#
|
#
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
module REXML
|
module REXML
|
||||||
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
|
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
|
||||||
DATE = "2008/019"
|
DATE = "2008/019"
|
||||||
VERSION = "3.1.7.3"
|
VERSION = "3.1.8"
|
||||||
REVISION = %w$Revision$[1] || ''
|
REVISION = ""
|
||||||
|
|
||||||
Copyright = COPYRIGHT
|
Copyright = COPYRIGHT
|
||||||
Version = VERSION
|
Version = VERSION
|
||||||
|
|
|
@ -254,6 +254,7 @@ module REXML
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
end
|
end
|
||||||
|
@er_source.seek(pos)
|
||||||
rescue IOError
|
rescue IOError
|
||||||
pos = -1
|
pos = -1
|
||||||
line = -1
|
line = -1
|
||||||
|
|
|
@ -96,27 +96,28 @@ module REXML
|
||||||
|
|
||||||
@raw = false
|
@raw = false
|
||||||
@parent = nil
|
@parent = nil
|
||||||
|
@entity_filter = nil
|
||||||
|
|
||||||
if parent
|
if parent
|
||||||
super( parent )
|
super( parent )
|
||||||
@raw = parent.raw
|
@raw = parent.raw
|
||||||
end
|
end
|
||||||
|
|
||||||
@raw = raw unless raw.nil?
|
|
||||||
@entity_filter = entity_filter
|
|
||||||
clear_cache
|
|
||||||
|
|
||||||
if arg.kind_of? String
|
if arg.kind_of? String
|
||||||
@string = arg.dup
|
@string = arg.dup
|
||||||
@string.squeeze!(" \n\t") unless respect_whitespace
|
|
||||||
elsif arg.kind_of? Text
|
elsif arg.kind_of? Text
|
||||||
@string = arg.to_s
|
@string = arg.instance_variable_get(:@string).dup
|
||||||
@raw = arg.raw
|
@raw = arg.raw
|
||||||
|
@entity_filter = arg.instance_variable_get(:@entity_filter)
|
||||||
elsif
|
elsif
|
||||||
raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})"
|
raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})"
|
||||||
end
|
end
|
||||||
|
|
||||||
@string.gsub!( /\r\n?/, "\n" )
|
@string.squeeze!(" \n\t") unless respect_whitespace
|
||||||
|
@string.gsub!(/\r\n?/, "\n")
|
||||||
|
@raw = raw unless raw.nil?
|
||||||
|
@entity_filter = entity_filter if entity_filter
|
||||||
|
clear_cache
|
||||||
|
|
||||||
Text.check(@string, illegal, doctype) if @raw
|
Text.check(@string, illegal, doctype) if @raw
|
||||||
end
|
end
|
||||||
|
@ -181,7 +182,7 @@ module REXML
|
||||||
|
|
||||||
|
|
||||||
def clone
|
def clone
|
||||||
return Text.new(self)
|
return Text.new(self, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,9 +227,7 @@ module REXML
|
||||||
# u.to_s #-> "sean russell"
|
# u.to_s #-> "sean russell"
|
||||||
def to_s
|
def to_s
|
||||||
return @string if @raw
|
return @string if @raw
|
||||||
return @normalized if @normalized
|
@normalized ||= Text::normalize( @string, doctype, @entity_filter )
|
||||||
|
|
||||||
@normalized = Text::normalize( @string, doctype, @entity_filter )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
|
@ -249,8 +248,7 @@ module REXML
|
||||||
# u = Text.new( "sean russell", false, nil, true )
|
# u = Text.new( "sean russell", false, nil, true )
|
||||||
# u.value #-> "sean russell"
|
# u.value #-> "sean russell"
|
||||||
def value
|
def value
|
||||||
return @unnormalized if @unnormalized
|
@unnormalized ||= Text::unnormalize( @string, doctype )
|
||||||
@unnormalized = Text::unnormalize( @string, doctype )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sets the contents of this text node. This expects the text to be
|
# Sets the contents of this text node. This expects the text to be
|
||||||
|
@ -266,16 +264,16 @@ module REXML
|
||||||
@raw = false
|
@raw = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def wrap(string, width, addnewline=false)
|
def wrap(string, width, addnewline=false)
|
||||||
# Recursively wrap string at width.
|
# Recursively wrap string at width.
|
||||||
return string if string.length <= width
|
return string if string.length <= width
|
||||||
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
|
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
|
||||||
if addnewline then
|
if addnewline then
|
||||||
return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
||||||
else
|
else
|
||||||
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def indent_text(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
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
require_relative 'encoding'
|
require_relative 'encoding'
|
||||||
require_relative 'source'
|
require_relative 'source'
|
||||||
|
|
||||||
|
@ -7,11 +8,11 @@ module REXML
|
||||||
class XMLDecl < Child
|
class XMLDecl < Child
|
||||||
include Encoding
|
include Encoding
|
||||||
|
|
||||||
DEFAULT_VERSION = "1.0";
|
DEFAULT_VERSION = "1.0"
|
||||||
DEFAULT_ENCODING = "UTF-8";
|
DEFAULT_ENCODING = "UTF-8"
|
||||||
DEFAULT_STANDALONE = "no";
|
DEFAULT_STANDALONE = "no"
|
||||||
START = '<\?xml';
|
START = "<?xml"
|
||||||
STOP = '\?>';
|
STOP = "?>"
|
||||||
|
|
||||||
attr_accessor :version, :standalone
|
attr_accessor :version, :standalone
|
||||||
attr_reader :writeencoding, :writethis
|
attr_reader :writeencoding, :writethis
|
||||||
|
@ -46,9 +47,9 @@ module REXML
|
||||||
# Ignored
|
# Ignored
|
||||||
def write(writer, indent=-1, transitive=false, ie_hack=false)
|
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
|
||||||
writer << START.sub(/\\/u, '')
|
writer << START
|
||||||
writer << " #{content encoding}"
|
writer << " #{content encoding}"
|
||||||
writer << STOP.sub(/\\/u, '')
|
writer << STOP
|
||||||
end
|
end
|
||||||
|
|
||||||
def ==( other )
|
def ==( other )
|
||||||
|
@ -102,14 +103,26 @@ module REXML
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
START.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '')
|
"#{START} ... #{STOP}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def content(enc)
|
def content(enc)
|
||||||
rv = "version='#@version'"
|
context = nil
|
||||||
rv << " encoding='#{enc}'" if @writeencoding || enc !~ /\Autf-8\z/i
|
context = parent.context if parent
|
||||||
rv << " standalone='#@standalone'" if @standalone
|
if context and context[:prologue_quote] == :quote
|
||||||
|
quote = "\""
|
||||||
|
else
|
||||||
|
quote = "'"
|
||||||
|
end
|
||||||
|
|
||||||
|
rv = "version=#{quote}#{@version}#{quote}"
|
||||||
|
if @writeencoding or enc !~ /\Autf-8\z/i
|
||||||
|
rv << " encoding=#{quote}#{enc}#{quote}"
|
||||||
|
end
|
||||||
|
if @standalone
|
||||||
|
rv << " standalone=#{quote}#{@standalone}#{quote}"
|
||||||
|
end
|
||||||
rv
|
rv
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe "REXML::Attribute#inspect" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not escape text" do
|
it "does not escape text" do
|
||||||
a = REXML::Attribute.new("&&", "<>")
|
a = REXML::Attribute.new("name", "<>")
|
||||||
a.inspect.should == "&&='<>'"
|
a.inspect.should == "name='<>'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="ISO-8859-1"?><?pos="3"?>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<!-- generated by hnb 1.9.17 (http://hnb.sourceforge.net) -->
|
<!-- generated by hnb 1.9.17 (http://hnb.sourceforge.net) -->
|
||||||
|
|
||||||
<!DOCTYPE tree[
|
<!DOCTYPE tree[
|
||||||
|
|
19
test/rexml/formatter/test_default.rb
Normal file
19
test/rexml/formatter/test_default.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
require_relative "../rexml_test_utils"
|
||||||
|
|
||||||
|
module REXMLTests
|
||||||
|
class DefaultFormatterTest < Test::Unit::TestCase
|
||||||
|
def format(node)
|
||||||
|
formatter = REXML::Formatters::Default.new
|
||||||
|
output = ""
|
||||||
|
formatter.write(node, output)
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
class InstructionTest < self
|
||||||
|
def test_content_nil
|
||||||
|
instruction = REXML::Instruction.new("target")
|
||||||
|
assert_equal("<?target?>", format(instruction))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
38
test/rexml/parse/test_element.rb
Normal file
38
test/rexml/parse/test_element.rb
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
require "test/unit"
|
||||||
|
require "rexml/document"
|
||||||
|
|
||||||
|
module REXMLTests
|
||||||
|
class TestParseElement < Test::Unit::TestCase
|
||||||
|
def parse(xml)
|
||||||
|
REXML::Document.new(xml)
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInvalid < self
|
||||||
|
def test_no_end_tag
|
||||||
|
exception = assert_raise(REXML::ParseException) do
|
||||||
|
parse("<a></")
|
||||||
|
end
|
||||||
|
assert_equal(<<-DETAIL.chomp, exception.to_s)
|
||||||
|
Missing end tag for 'a'
|
||||||
|
Line: 1
|
||||||
|
Position: 5
|
||||||
|
Last 80 unconsumed characters:
|
||||||
|
</
|
||||||
|
DETAIL
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_empty_namespace_attribute_name
|
||||||
|
exception = assert_raise(REXML::ParseException) do
|
||||||
|
parse("<x :a=\"\"></x>")
|
||||||
|
end
|
||||||
|
assert_equal(<<-DETAIL.chomp, exception.to_s)
|
||||||
|
Invalid attribute name: <:a="">
|
||||||
|
Line: 1
|
||||||
|
Position: 9
|
||||||
|
Last 80 unconsumed characters:
|
||||||
|
|
||||||
|
DETAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
25
test/rexml/parse/test_processing_instruction.rb
Normal file
25
test/rexml/parse/test_processing_instruction.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
require "test/unit"
|
||||||
|
require "rexml/document"
|
||||||
|
|
||||||
|
module REXMLTests
|
||||||
|
class TestParseProcessinInstruction < Test::Unit::TestCase
|
||||||
|
def parse(xml)
|
||||||
|
REXML::Document.new(xml)
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestInvalid < self
|
||||||
|
def test_no_name
|
||||||
|
exception = assert_raise(REXML::ParseException) do
|
||||||
|
parse("<??>")
|
||||||
|
end
|
||||||
|
assert_equal(<<-DETAIL.chomp, exception.to_s)
|
||||||
|
Invalid processing instruction node
|
||||||
|
Line: 1
|
||||||
|
Position: 4
|
||||||
|
Last 80 unconsumed characters:
|
||||||
|
<??>
|
||||||
|
DETAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,7 +12,7 @@ class TestTreeParser < Test::Unit::TestCase
|
||||||
parse(xml)
|
parse(xml)
|
||||||
end
|
end
|
||||||
assert_equal(<<-MESSAGE, exception.to_s)
|
assert_equal(<<-MESSAGE, exception.to_s)
|
||||||
Missing end tag for 'root' (got "not-root")
|
Missing end tag for 'root' (got 'not-root')
|
||||||
Line: 1
|
Line: 1
|
||||||
Position: #{xml.bytesize}
|
Position: #{xml.bytesize}
|
||||||
Last 80 unconsumed characters:
|
Last 80 unconsumed characters:
|
||||||
|
|
|
@ -55,7 +55,7 @@ class TestUltraLightParser < Test::Unit::TestCase
|
||||||
normalized_doctype[1] = normalized_parent
|
normalized_doctype[1] = normalized_parent
|
||||||
normalized_doctype
|
normalized_doctype
|
||||||
when :start_element
|
when :start_element
|
||||||
tag, parent, name, attributes, *children = child
|
tag, _parent, name, attributes, *children = child
|
||||||
normalized_parent = :parent
|
normalized_parent = :parent
|
||||||
normalized_children = children.collect do |sub_child|
|
normalized_children = children.collect do |sub_child|
|
||||||
normalize_child(sub_child)
|
normalize_child(sub_child)
|
||||||
|
|
14
test/rexml/test_attribute.rb
Normal file
14
test/rexml/test_attribute.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
require_relative "rexml_test_utils"
|
||||||
|
|
||||||
|
module REXMLTests
|
||||||
|
class AttributeTest < Test::Unit::TestCase
|
||||||
|
def test_empty_prefix
|
||||||
|
error = assert_raise(ArgumentError) do
|
||||||
|
REXML::Attribute.new(":x")
|
||||||
|
end
|
||||||
|
assert_equal("name must be " +
|
||||||
|
"\#{PREFIX}:\#{LOCAL_NAME} or \#{LOCAL_NAME}: <\":x\">",
|
||||||
|
error.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1274,14 +1274,15 @@ EOL
|
||||||
|
|
||||||
def test_ticket_21
|
def test_ticket_21
|
||||||
src = "<foo bar=value/>"
|
src = "<foo bar=value/>"
|
||||||
assert_raise( ParseException, "invalid XML should be caught" ) {
|
exception = assert_raise(ParseException) do
|
||||||
Document.new(src)
|
Document.new(src)
|
||||||
}
|
|
||||||
begin
|
|
||||||
Document.new(src)
|
|
||||||
rescue
|
|
||||||
assert_match( /missing attribute quote/, $!.message )
|
|
||||||
end
|
end
|
||||||
|
assert_equal(<<-DETAIL, exception.to_s)
|
||||||
|
Missing attribute value start quote: <bar>
|
||||||
|
Line: 1
|
||||||
|
Position: 16
|
||||||
|
Last 80 unconsumed characters:
|
||||||
|
DETAIL
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ticket_63
|
def test_ticket_63
|
||||||
|
|
|
@ -1,68 +1,92 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
require 'test/unit'
|
|
||||||
require 'rexml/document'
|
require_relative "rexml_test_utils"
|
||||||
|
|
||||||
module REXMLTests
|
module REXMLTests
|
||||||
class TestDocTypeAccessor < Test::Unit::TestCase
|
class TestDocTypeAccessor < Test::Unit::TestCase
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@sysid = "urn:x-test:sysid1"
|
@sysid = "urn:x-test:sysid1"
|
||||||
@notid1 = "urn:x-test:notation1"
|
@notation_id1 = "urn:x-test:notation1"
|
||||||
@notid2 = "urn:x-test:notation2"
|
@notation_id2 = "urn:x-test:notation2"
|
||||||
document_string1 = <<-"XMLEND"
|
xml_system = <<-XML
|
||||||
<!DOCTYPE r SYSTEM "#{@sysid}" [
|
<!DOCTYPE root SYSTEM "#{@sysid}" [
|
||||||
<!NOTATION n1 SYSTEM "#{@notid1}">
|
<!NOTATION n1 SYSTEM "#{@notation_id1}">
|
||||||
<!NOTATION n2 SYSTEM "#{@notid2}">
|
<!NOTATION n2 SYSTEM "#{@notation_id2}">
|
||||||
]>
|
]>
|
||||||
<r/>
|
<root/>
|
||||||
XMLEND
|
XML
|
||||||
@doctype1 = REXML::Document.new(document_string1).doctype
|
@doc_type_system = REXML::Document.new(xml_system).doctype
|
||||||
|
|
||||||
@pubid = "TEST_ID"
|
@pubid = "TEST_ID"
|
||||||
document_string2 = <<-"XMLEND"
|
xml_public = <<-XML
|
||||||
<!DOCTYPE r PUBLIC "#{@pubid}">
|
<!DOCTYPE root PUBLIC "#{@pubid}">
|
||||||
<r/>
|
<root/>
|
||||||
XMLEND
|
XML
|
||||||
@doctype2 = REXML::Document.new(document_string2).doctype
|
@doc_type_public = REXML::Document.new(xml_public).doctype
|
||||||
|
|
||||||
document_string3 = <<-"XMLEND"
|
|
||||||
<!DOCTYPE r PUBLIC "#{@pubid}" "#{@sysid}">
|
|
||||||
<r/>
|
|
||||||
XMLEND
|
|
||||||
@doctype3 = REXML::Document.new(document_string3).doctype
|
|
||||||
|
|
||||||
|
xml_public_system = <<-XML
|
||||||
|
<!DOCTYPE root PUBLIC "#{@pubid}" "#{@sysid}">
|
||||||
|
<root/>
|
||||||
|
XML
|
||||||
|
@doc_type_public_system = REXML::Document.new(xml_public_system).doctype
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_public
|
def test_public
|
||||||
assert_equal(nil, @doctype1.public)
|
assert_equal([
|
||||||
assert_equal(@pubid, @doctype2.public)
|
nil,
|
||||||
assert_equal(@pubid, @doctype3.public)
|
@pubid,
|
||||||
|
@pubid,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
@doc_type_system.public,
|
||||||
|
@doc_type_public.public,
|
||||||
|
@doc_type_public_system.public,
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s
|
||||||
|
assert_equal("<!DOCTYPE root PUBLIC \"#{@pubid}\" \"#{@sysid}\">",
|
||||||
|
@doc_type_public_system.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s_apostrophe
|
||||||
|
@doc_type_public_system.parent.context[:prologue_quote] = :apostrophe
|
||||||
|
assert_equal("<!DOCTYPE root PUBLIC '#{@pubid}' '#{@sysid}'>",
|
||||||
|
@doc_type_public_system.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_system
|
def test_system
|
||||||
assert_equal(@sysid, @doctype1.system)
|
assert_equal([
|
||||||
assert_equal(nil, @doctype2.system)
|
@sysid,
|
||||||
assert_equal(@sysid, @doctype3.system)
|
nil,
|
||||||
|
@sysid,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
@doc_type_system.system,
|
||||||
|
@doc_type_public.system,
|
||||||
|
@doc_type_public_system.system,
|
||||||
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_notation
|
def test_notation
|
||||||
assert_equal(@notid1, @doctype1.notation("n1").system)
|
assert_equal([
|
||||||
assert_equal(@notid2, @doctype1.notation("n2").system)
|
@notation_id1,
|
||||||
|
@notation_id2,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
@doc_type_system.notation("n1").system,
|
||||||
|
@doc_type_system.notation("n2").system,
|
||||||
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_notations
|
def test_notations
|
||||||
notations = @doctype1.notations
|
notations = @doc_type_system.notations
|
||||||
assert_equal(2, notations.length)
|
assert_equal([
|
||||||
assert_equal(@notid1, find_notation(notations, "n1").system)
|
@notation_id1,
|
||||||
assert_equal(@notid2, find_notation(notations, "n2").system)
|
@notation_id2,
|
||||||
|
],
|
||||||
|
notations.collect(&:system))
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_notation(notations, name)
|
|
||||||
notations.find { |notation|
|
|
||||||
name == notation.name
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TestNotationDeclPublic < Test::Unit::TestCase
|
class TestNotationDeclPublic < Test::Unit::TestCase
|
||||||
|
@ -82,6 +106,19 @@ module REXMLTests
|
||||||
decl(@id, @uri).to_s)
|
decl(@id, @uri).to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_to_s_apostrophe
|
||||||
|
document = REXML::Document.new(<<-XML)
|
||||||
|
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
|
||||||
|
#{decl(@id, @uri).to_s}
|
||||||
|
]>
|
||||||
|
<root/>
|
||||||
|
XML
|
||||||
|
document.context[:prologue_quote] = :apostrophe
|
||||||
|
notation = document.doctype.notations[0]
|
||||||
|
assert_equal("<!NOTATION #{@name} PUBLIC '#{@id}' '#{@uri}'>",
|
||||||
|
notation.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def decl(id, uri)
|
def decl(id, uri)
|
||||||
REXML::NotationDecl.new(@name, "PUBLIC", id, uri)
|
REXML::NotationDecl.new(@name, "PUBLIC", id, uri)
|
||||||
|
@ -99,6 +136,19 @@ module REXMLTests
|
||||||
decl(@id).to_s)
|
decl(@id).to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_to_s_apostrophe
|
||||||
|
document = REXML::Document.new(<<-XML)
|
||||||
|
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
|
||||||
|
#{decl(@id).to_s}
|
||||||
|
]>
|
||||||
|
<root/>
|
||||||
|
XML
|
||||||
|
document.context[:prologue_quote] = :apostrophe
|
||||||
|
notation = document.doctype.notations[0]
|
||||||
|
assert_equal("<!NOTATION #{@name} SYSTEM '#{@id}'>",
|
||||||
|
notation.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def decl(id)
|
def decl(id)
|
||||||
REXML::NotationDecl.new(@name, "SYSTEM", id, nil)
|
REXML::NotationDecl.new(@name, "SYSTEM", id, nil)
|
||||||
|
|
14
test/rexml/test_instruction.rb
Normal file
14
test/rexml/test_instruction.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
require_relative "rexml_test_utils"
|
||||||
|
|
||||||
|
module REXMLTests
|
||||||
|
class InstructionTest < Test::Unit::TestCase
|
||||||
|
def test_target_nil
|
||||||
|
error = assert_raise(ArgumentError) do
|
||||||
|
REXML::Instruction.new(nil)
|
||||||
|
end
|
||||||
|
assert_equal("processing instruction target must be String or " +
|
||||||
|
"REXML::Instruction: <nil>",
|
||||||
|
error.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,8 +15,8 @@ module REXMLTests
|
||||||
def test_listener
|
def test_listener
|
||||||
data = %Q{<session1 user="han" password="rootWeiler" />\n<session2 user="han" password="rootWeiler" />}
|
data = %Q{<session1 user="han" password="rootWeiler" />\n<session2 user="han" password="rootWeiler" />}
|
||||||
|
|
||||||
b = RequestReader.new( data )
|
RequestReader.new( data )
|
||||||
b = RequestReader.new( data )
|
RequestReader.new( data )
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ticket_49
|
def test_ticket_49
|
||||||
|
|
|
@ -5,6 +5,52 @@ module REXMLTests
|
||||||
class TextTester < Test::Unit::TestCase
|
class TextTester < Test::Unit::TestCase
|
||||||
include REXML
|
include REXML
|
||||||
|
|
||||||
|
def test_new_text_response_whitespace_default
|
||||||
|
text = Text.new("a b\t\tc", true)
|
||||||
|
assert_equal("a b\tc", Text.new(text).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_text_response_whitespace_true
|
||||||
|
text = Text.new("a b\t\tc", true)
|
||||||
|
assert_equal("a b\t\tc", Text.new(text, true).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_text_raw_default
|
||||||
|
text = Text.new("&lt;", false, nil, true)
|
||||||
|
assert_equal("&lt;", Text.new(text).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_text_raw_false
|
||||||
|
text = Text.new("&lt;", false, nil, true)
|
||||||
|
assert_equal("&amp;lt;", Text.new(text, false, nil, false).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_text_entity_filter_default
|
||||||
|
document = REXML::Document.new(<<-XML)
|
||||||
|
<!DOCTYPE root [
|
||||||
|
<!ENTITY a "aaa">
|
||||||
|
<!ENTITY b "bbb">
|
||||||
|
]>
|
||||||
|
<root/>
|
||||||
|
XML
|
||||||
|
text = Text.new("aaa bbb", false, document.root, nil, ["a"])
|
||||||
|
assert_equal("aaa &b;",
|
||||||
|
Text.new(text, false, document.root).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_text_entity_filter_custom
|
||||||
|
document = REXML::Document.new(<<-XML)
|
||||||
|
<!DOCTYPE root [
|
||||||
|
<!ENTITY a "aaa">
|
||||||
|
<!ENTITY b "bbb">
|
||||||
|
]>
|
||||||
|
<root/>
|
||||||
|
XML
|
||||||
|
text = Text.new("aaa bbb", false, document.root, nil, ["a"])
|
||||||
|
assert_equal("&a; bbb",
|
||||||
|
Text.new(text, false, document.root, nil, ["b"]).to_s)
|
||||||
|
end
|
||||||
|
|
||||||
def test_shift_operator_chain
|
def test_shift_operator_chain
|
||||||
text = Text.new("original\r\n")
|
text = Text.new("original\r\n")
|
||||||
text << "append1\r\n" << "append2\r\n"
|
text << "append1\r\n" << "append2\r\n"
|
||||||
|
@ -18,5 +64,11 @@ module REXMLTests
|
||||||
text << "append3\r\n" << "append4\r\n"
|
text << "append3\r\n" << "append4\r\n"
|
||||||
assert_equal("original\nappend1\nappend2\nappend3\nappend4\n", text.to_s)
|
assert_equal("original\nappend1\nappend2\nappend3\nappend4\n", text.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_clone
|
||||||
|
text = Text.new("&lt; <")
|
||||||
|
assert_equal(text.to_s,
|
||||||
|
text.clone.to_s)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
#
|
#
|
||||||
# Created by Henrik Mårtensson on 2007-02-18.
|
# Created by Henrik Mårtensson on 2007-02-18.
|
||||||
|
@ -10,11 +9,11 @@ require "test/unit"
|
||||||
module REXMLTests
|
module REXMLTests
|
||||||
class TestXmlDeclaration < Test::Unit::TestCase
|
class TestXmlDeclaration < Test::Unit::TestCase
|
||||||
def setup
|
def setup
|
||||||
xml = <<-'END_XML'
|
xml = <<-XML
|
||||||
<?xml encoding= 'UTF-8' standalone='yes'?>
|
<?xml encoding= 'UTF-8' standalone='yes'?>
|
||||||
<root>
|
<root>
|
||||||
</root>
|
</root>
|
||||||
END_XML
|
XML
|
||||||
@doc = REXML::Document.new xml
|
@doc = REXML::Document.new xml
|
||||||
@root = @doc.root
|
@root = @doc.root
|
||||||
@xml_declaration = @doc.children[0]
|
@xml_declaration = @doc.children[0]
|
||||||
|
@ -32,5 +31,12 @@ module REXMLTests
|
||||||
assert_kind_of(REXML::XMLDecl, @root.previous_sibling.previous_sibling)
|
assert_kind_of(REXML::XMLDecl, @root.previous_sibling.previous_sibling)
|
||||||
assert_kind_of(REXML::Element, @xml_declaration.next_sibling.next_sibling)
|
assert_kind_of(REXML::Element, @xml_declaration.next_sibling.next_sibling)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_write_prologue_quote
|
||||||
|
@doc.context[:prologue_quote] = :quote
|
||||||
|
assert_equal("<?xml version=\"1.0\" " +
|
||||||
|
"encoding=\"UTF-8\" standalone=\"yes\"?>",
|
||||||
|
@xml_declaration.to_s)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue