1825 lines
65 KiB
Diff
1825 lines
65 KiB
Diff
|
|
From 20017eea807e8fa386aa5c79ae779004d8b366dd Mon Sep 17 00:00:00 2001
|
||
|
|
From: Sutou Kouhei <kou@clear-code.com>
|
||
|
|
Date: Tue, 25 Jun 2024 11:26:33 +0900
|
||
|
|
Subject: [PATCH] Add 3.3.1 entry
|
||
|
|
|
||
|
|
Backport from https://github.com/ruby/rexml/tree/v3.3.1/lib/rexml
|
||
|
|
|
||
|
|
---
|
||
|
|
.../gems/rexml-3.2.5/lib/rexml/attribute.rb | 23 +-
|
||
|
|
.../gems/rexml-3.2.5/lib/rexml/document.rb | 2 +-
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/element.rb | 23 +-
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb | 40 +-
|
||
|
|
.../lib/rexml/formatters/pretty.rb | 4 +-
|
||
|
|
.../gems/rexml-3.2.5/lib/rexml/functions.rb | 3 +-
|
||
|
|
.../gems/rexml-3.2.5/lib/rexml/namespace.rb | 12 +-
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/node.rb | 12 +-
|
||
|
|
.../rexml-3.2.5/lib/rexml/parseexception.rb | 1 +
|
||
|
|
.../lib/rexml/parsers/baseparser.rb | 521 ++++++++++--------
|
||
|
|
.../lib/rexml/parsers/treeparser.rb | 23 +-
|
||
|
|
.../lib/rexml/parsers/xpathparser.rb | 222 +++++---
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb | 4 +-
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/source.rb | 220 ++++----
|
||
|
|
.bundle/gems/rexml-3.2.5/lib/rexml/text.rb | 10 +-
|
||
|
|
.../rexml-3.2.5/lib/rexml/xpath_parser.rb | 10 +-
|
||
|
|
16 files changed, 627 insertions(+), 503 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/attribute.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/attribute.rb
|
||
|
|
index 8933a01..11893a9 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/attribute.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/attribute.rb
|
||
|
|
@@ -1,4 +1,4 @@
|
||
|
|
-# frozen_string_literal: false
|
||
|
|
+# frozen_string_literal: true
|
||
|
|
require_relative "namespace"
|
||
|
|
require_relative 'text'
|
||
|
|
|
||
|
|
@@ -13,9 +13,6 @@ module REXML
|
||
|
|
|
||
|
|
# The element to which this attribute belongs
|
||
|
|
attr_reader :element
|
||
|
|
- # The normalized value of this attribute. That is, the attribute with
|
||
|
|
- # entities intact.
|
||
|
|
- attr_writer :normalized
|
||
|
|
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
|
||
|
|
|
||
|
|
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
|
||
|
|
@@ -122,10 +119,13 @@ module REXML
|
||
|
|
# b = Attribute.new( "ns:x", "y" )
|
||
|
|
# b.to_string # -> "ns:x='y'"
|
||
|
|
def to_string
|
||
|
|
+ value = to_s
|
||
|
|
if @element and @element.context and @element.context[:attribute_quote] == :quote
|
||
|
|
- %Q^#@expanded_name="#{to_s().gsub(/"/, '"')}"^
|
||
|
|
+ value = value.gsub('"', '"') if value.include?('"')
|
||
|
|
+ %Q^#@expanded_name="#{value}"^
|
||
|
|
else
|
||
|
|
- "#@expanded_name='#{to_s().gsub(/'/, ''')}'"
|
||
|
|
+ value = value.gsub("'", ''') if value.include?("'")
|
||
|
|
+ "#@expanded_name='#{value}'"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
@@ -141,7 +141,6 @@ module REXML
|
||
|
|
return @normalized if @normalized
|
||
|
|
|
||
|
|
@normalized = Text::normalize( @unnormalized, doctype )
|
||
|
|
- @unnormalized = nil
|
||
|
|
@normalized
|
||
|
|
end
|
||
|
|
|
||
|
|
@@ -150,10 +149,16 @@ module REXML
|
||
|
|
def value
|
||
|
|
return @unnormalized if @unnormalized
|
||
|
|
@unnormalized = Text::unnormalize( @normalized, doctype )
|
||
|
|
- @normalized = nil
|
||
|
|
@unnormalized
|
||
|
|
end
|
||
|
|
|
||
|
|
+ # The normalized value of this attribute. That is, the attribute with
|
||
|
|
+ # entities intact.
|
||
|
|
+ def normalized=(new_normalized)
|
||
|
|
+ @normalized = new_normalized
|
||
|
|
+ @unnormalized = nil
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
# Returns a copy of this attribute
|
||
|
|
def clone
|
||
|
|
Attribute.new self
|
||
|
|
@@ -190,7 +195,7 @@ module REXML
|
||
|
|
end
|
||
|
|
|
||
|
|
def inspect
|
||
|
|
- rv = ""
|
||
|
|
+ rv = +""
|
||
|
|
write( rv )
|
||
|
|
rv
|
||
|
|
end
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/document.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/document.rb
|
||
|
|
index 2edeb98..b1caa02 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/document.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/document.rb
|
||
|
|
@@ -69,7 +69,7 @@ module REXML
|
||
|
|
# d.to_s # => "<root><foo>Foo</foo><bar>Bar</bar></root>"
|
||
|
|
#
|
||
|
|
# When argument +document+ is given, it must be an existing
|
||
|
|
- # document object, whose context and attributes (but not chidren)
|
||
|
|
+ # document object, whose context and attributes (but not children)
|
||
|
|
# are cloned into the new document:
|
||
|
|
#
|
||
|
|
# d = REXML::Document.new(xml_string)
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
|
||
|
|
index 4c21dbd..a5808d7 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
|
||
|
|
@@ -7,14 +7,6 @@ require_relative "xpath"
|
||
|
|
require_relative "parseexception"
|
||
|
|
|
||
|
|
module REXML
|
||
|
|
- # An implementation note about namespaces:
|
||
|
|
- # As we parse, when we find namespaces we put them in a hash and assign
|
||
|
|
- # them a unique ID. We then convert the namespace prefix for the node
|
||
|
|
- # to the unique ID. This makes namespace lookup much faster for the
|
||
|
|
- # cost of extra memory use. We save the namespace prefix for the
|
||
|
|
- # context node and convert it back when we write it.
|
||
|
|
- @@namespaces = {}
|
||
|
|
-
|
||
|
|
# An \REXML::Element object represents an XML element.
|
||
|
|
#
|
||
|
|
# An element:
|
||
|
|
@@ -989,7 +981,7 @@ module REXML
|
||
|
|
# :call-seq:
|
||
|
|
# has_text? -> true or false
|
||
|
|
#
|
||
|
|
- # Returns +true if the element has one or more text noded,
|
||
|
|
+ # Returns +true+ if the element has one or more text noded,
|
||
|
|
# +false+ otherwise:
|
||
|
|
#
|
||
|
|
# d = REXML::Document.new '<a><b/>text<c/></a>'
|
||
|
|
@@ -1006,7 +998,7 @@ module REXML
|
||
|
|
# text(xpath = nil) -> text_string or nil
|
||
|
|
#
|
||
|
|
# Returns the text string from the first text node child
|
||
|
|
- # in a specified element, if it exists, # +nil+ otherwise.
|
||
|
|
+ # in a specified element, if it exists, +nil+ otherwise.
|
||
|
|
#
|
||
|
|
# With no argument, returns the text from the first text node in +self+:
|
||
|
|
#
|
||
|
|
@@ -1014,7 +1006,7 @@ module REXML
|
||
|
|
# d.root.text.class # => String
|
||
|
|
# d.root.text # => "some text "
|
||
|
|
#
|
||
|
|
- # With argument +xpath+, returns text from the the first text node
|
||
|
|
+ # With argument +xpath+, returns text from the first text node
|
||
|
|
# in the element that matches +xpath+:
|
||
|
|
#
|
||
|
|
# d.root.text(1) # => "this is bold!"
|
||
|
|
@@ -1284,16 +1276,11 @@ module REXML
|
||
|
|
# document.root.attribute("x", "a") # => a:x='a:x'
|
||
|
|
#
|
||
|
|
def attribute( name, namespace=nil )
|
||
|
|
- prefix = nil
|
||
|
|
- if namespaces.respond_to? :key
|
||
|
|
- prefix = namespaces.key(namespace) if namespace
|
||
|
|
- else
|
||
|
|
- prefix = namespaces.index(namespace) if namespace
|
||
|
|
- end
|
||
|
|
+ prefix = namespaces.key(namespace) if namespace
|
||
|
|
prefix = nil if prefix == 'xmlns'
|
||
|
|
|
||
|
|
ret_val =
|
||
|
|
- attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
|
||
|
|
+ attributes.get_attribute( prefix ? "#{prefix}:#{name}" : name )
|
||
|
|
|
||
|
|
return ret_val unless ret_val.nil?
|
||
|
|
return nil if prefix.nil?
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
|
||
|
|
index 89a9e84..573db69 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
|
||
|
|
@@ -132,24 +132,34 @@ module REXML
|
||
|
|
# then:
|
||
|
|
# doctype.entity('yada').value #-> "nanoo bar nanoo"
|
||
|
|
def value
|
||
|
|
- if @value
|
||
|
|
- matches = @value.scan(PEREFERENCE_RE)
|
||
|
|
- rv = @value.clone
|
||
|
|
- if @parent
|
||
|
|
- sum = 0
|
||
|
|
- matches.each do |entity_reference|
|
||
|
|
- entity_value = @parent.entity( entity_reference[0] )
|
||
|
|
- if sum + entity_value.bytesize > Security.entity_expansion_text_limit
|
||
|
|
- raise "entity expansion has grown too large"
|
||
|
|
- else
|
||
|
|
- sum += entity_value.bytesize
|
||
|
|
- end
|
||
|
|
- rv.gsub!( /%#{entity_reference.join};/um, entity_value )
|
||
|
|
+ @resolved_value ||= resolve_value
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ def parent=(other)
|
||
|
|
+ @resolved_value = nil
|
||
|
|
+ super
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ private
|
||
|
|
+ def resolve_value
|
||
|
|
+ return nil if @value.nil?
|
||
|
|
+ return @value unless @value.match?(PEREFERENCE_RE)
|
||
|
|
+
|
||
|
|
+ matches = @value.scan(PEREFERENCE_RE)
|
||
|
|
+ rv = @value.clone
|
||
|
|
+ if @parent
|
||
|
|
+ sum = 0
|
||
|
|
+ matches.each do |entity_reference|
|
||
|
|
+ entity_value = @parent.entity( entity_reference[0] )
|
||
|
|
+ if sum + entity_value.bytesize > Security.entity_expansion_text_limit
|
||
|
|
+ raise "entity expansion has grown too large"
|
||
|
|
+ else
|
||
|
|
+ sum += entity_value.bytesize
|
||
|
|
end
|
||
|
|
+ rv.gsub!( /%#{entity_reference.join};/um, entity_value )
|
||
|
|
end
|
||
|
|
- return rv
|
||
|
|
end
|
||
|
|
- nil
|
||
|
|
+ rv
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb
|
||
|
|
index 562ef94..a1198b7 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb
|
||
|
|
@@ -1,4 +1,4 @@
|
||
|
|
-# frozen_string_literal: false
|
||
|
|
+# frozen_string_literal: true
|
||
|
|
require_relative 'default'
|
||
|
|
|
||
|
|
module REXML
|
||
|
|
@@ -58,7 +58,7 @@ module REXML
|
||
|
|
skip = false
|
||
|
|
if compact
|
||
|
|
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
|
||
|
|
- string = ""
|
||
|
|
+ string = +""
|
||
|
|
old_level = @level
|
||
|
|
@level = 0
|
||
|
|
node.children.each { |child| write( child, string ) }
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/functions.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/functions.rb
|
||
|
|
index 77926bf..4c11461 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/functions.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/functions.rb
|
||
|
|
@@ -262,11 +262,10 @@ module REXML
|
||
|
|
string(string).length
|
||
|
|
end
|
||
|
|
|
||
|
|
- # UNTESTED
|
||
|
|
def Functions::normalize_space( string=nil )
|
||
|
|
string = string(@@context[:node]) if string.nil?
|
||
|
|
if string.kind_of? Array
|
||
|
|
- string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
|
||
|
|
+ string.collect{|x| x.to_s.strip.gsub(/\s+/um, ' ') if x}
|
||
|
|
else
|
||
|
|
string.to_s.strip.gsub(/\s+/um, ' ')
|
||
|
|
end
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/namespace.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/namespace.rb
|
||
|
|
index 924edf9..2e67252 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/namespace.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/namespace.rb
|
||
|
|
@@ -1,4 +1,4 @@
|
||
|
|
-# frozen_string_literal: false
|
||
|
|
+# frozen_string_literal: true
|
||
|
|
|
||
|
|
require_relative 'xmltokens'
|
||
|
|
|
||
|
|
@@ -10,13 +10,17 @@ module REXML
|
||
|
|
# The expanded name of the object, valid if name is set
|
||
|
|
attr_accessor :prefix
|
||
|
|
include XMLTokens
|
||
|
|
+ NAME_WITHOUT_NAMESPACE = /\A#{NCNAME_STR}\z/
|
||
|
|
NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
|
||
|
|
|
||
|
|
# Sets the name and the expanded name
|
||
|
|
def name=( name )
|
||
|
|
@expanded_name = name
|
||
|
|
- case name
|
||
|
|
- when NAMESPLIT
|
||
|
|
+ if name.match?(NAME_WITHOUT_NAMESPACE)
|
||
|
|
+ @prefix = ""
|
||
|
|
+ @namespace = ""
|
||
|
|
+ @name = name
|
||
|
|
+ elsif name =~ NAMESPLIT
|
||
|
|
if $1
|
||
|
|
@prefix = $1
|
||
|
|
else
|
||
|
|
@@ -24,7 +28,7 @@ module REXML
|
||
|
|
@namespace = ""
|
||
|
|
end
|
||
|
|
@name = $2
|
||
|
|
- when ""
|
||
|
|
+ elsif name == ""
|
||
|
|
@prefix = nil
|
||
|
|
@namespace = nil
|
||
|
|
@name = nil
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/node.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/node.rb
|
||
|
|
index 081caba..c771db7 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/node.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/node.rb
|
||
|
|
@@ -52,10 +52,14 @@ module REXML
|
||
|
|
|
||
|
|
# Visit all subnodes of +self+ recursively
|
||
|
|
def each_recursive(&block) # :yields: node
|
||
|
|
- self.elements.each {|node|
|
||
|
|
- block.call(node)
|
||
|
|
- node.each_recursive(&block)
|
||
|
|
- }
|
||
|
|
+ stack = []
|
||
|
|
+ each { |child| stack.unshift child if child.node_type == :element }
|
||
|
|
+ until stack.empty?
|
||
|
|
+ child = stack.pop
|
||
|
|
+ yield child
|
||
|
|
+ n = stack.size
|
||
|
|
+ child.each { |grandchild| stack.insert n, grandchild if grandchild.node_type == :element }
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
|
||
|
|
# Find (and return) first subnode (recursively) for which the block
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parseexception.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parseexception.rb
|
||
|
|
index 7b16cd1..e57d05f 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parseexception.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parseexception.rb
|
||
|
|
@@ -29,6 +29,7 @@ module REXML
|
||
|
|
err << "\nLine: #{line}\n"
|
||
|
|
err << "Position: #{position}\n"
|
||
|
|
err << "Last 80 unconsumed characters:\n"
|
||
|
|
+ err.force_encoding("ASCII-8BIT")
|
||
|
|
err << @source.buffer[0..80].force_encoding("ASCII-8BIT").gsub(/\n/, ' ')
|
||
|
|
end
|
||
|
|
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb
|
||
|
|
index 305b120..275372e 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb
|
||
|
|
@@ -1,4 +1,4 @@
|
||
|
|
-# frozen_string_literal: false
|
||
|
|
+# frozen_string_literal: true
|
||
|
|
require_relative '../parseexception'
|
||
|
|
require_relative '../undefinednamespaceexception'
|
||
|
|
require_relative '../source'
|
||
|
|
@@ -7,6 +7,17 @@ require "strscan"
|
||
|
|
|
||
|
|
module REXML
|
||
|
|
module Parsers
|
||
|
|
+ if StringScanner::Version < "3.0.8"
|
||
|
|
+ module StringScannerCaptures
|
||
|
|
+ refine StringScanner do
|
||
|
|
+ def captures
|
||
|
|
+ values_at(*(1...size))
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ using StringScannerCaptures
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
# = Using the Pull Parser
|
||
|
|
# <em>This API is experimental, and subject to change.</em>
|
||
|
|
# parser = PullParser.new( "<a>text<b att='val'/>txet</a>" )
|
||
|
|
@@ -96,7 +107,7 @@ module REXML
|
||
|
|
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
|
||
|
|
PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
|
||
|
|
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
|
||
|
|
- ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
|
||
|
|
+ ENTITYDECL = /\s*(?:#{GEDECL})|\s*(?:#{PEDECL})/um
|
||
|
|
|
||
|
|
NOTATIONDECL_START = /\A\s*<!NOTATION/um
|
||
|
|
EXTERNAL_ID_PUBLIC = /\A\s*PUBLIC\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}\s*/um
|
||
|
|
@@ -112,9 +123,29 @@ module REXML
|
||
|
|
"apos" => [/'/, "'", "'", /'/]
|
||
|
|
}
|
||
|
|
|
||
|
|
+ module Private
|
||
|
|
+ INSTRUCTION_END = /#{NAME}(\s+.*?)?\?>/um
|
||
|
|
+ TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
|
||
|
|
+ CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
|
||
|
|
+ ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
|
||
|
|
+ NAME_PATTERN = /\s*#{NAME}/um
|
||
|
|
+ GEDECL_PATTERN = "\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
|
||
|
|
+ PEDECL_PATTERN = "\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
|
||
|
|
+ ENTITYDECL_PATTERN = /(?:#{GEDECL_PATTERN})|(?:#{PEDECL_PATTERN})/um
|
||
|
|
+ CARRIAGE_RETURN_NEWLINE_PATTERN = /\r\n?/
|
||
|
|
+ CHARACTER_REFERENCES = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/
|
||
|
|
+ DEFAULT_ENTITIES_PATTERNS = {}
|
||
|
|
+ default_entities = ['gt', 'lt', 'quot', 'apos', 'amp']
|
||
|
|
+ default_entities.each do |term|
|
||
|
|
+ DEFAULT_ENTITIES_PATTERNS[term] = /&#{term};/
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ private_constant :Private
|
||
|
|
+
|
||
|
|
def initialize( source )
|
||
|
|
self.stream = source
|
||
|
|
@listeners = []
|
||
|
|
+ @prefixes = Set.new
|
||
|
|
end
|
||
|
|
|
||
|
|
def add_listener( listener )
|
||
|
|
@@ -180,6 +211,8 @@ module REXML
|
||
|
|
|
||
|
|
# Returns the next event. This is a +PullEvent+ object.
|
||
|
|
def pull
|
||
|
|
+ @source.drop_parsed_content
|
||
|
|
+
|
||
|
|
pull_event.tap do |event|
|
||
|
|
@listeners.each do |listener|
|
||
|
|
listener.receive event
|
||
|
|
@@ -192,236 +225,251 @@ module REXML
|
||
|
|
x, @closed = @closed, nil
|
||
|
|
return [ :end_element, x ]
|
||
|
|
end
|
||
|
|
- return [ :end_document ] if empty?
|
||
|
|
+ if empty?
|
||
|
|
+ if @document_status == :in_doctype
|
||
|
|
+ raise ParseException.new("Malformed DOCTYPE: unclosed", @source)
|
||
|
|
+ end
|
||
|
|
+ return [ :end_document ]
|
||
|
|
+ end
|
||
|
|
return @stack.shift if @stack.size > 0
|
||
|
|
#STDERR.puts @source.encoding
|
||
|
|
#STDERR.puts "BUFFER = #{@source.buffer.inspect}"
|
||
|
|
+
|
||
|
|
+ @source.ensure_buffer
|
||
|
|
if @document_status == nil
|
||
|
|
- word = @source.match( /\A((?:\s+)|(?:<[^>]*>))/um )
|
||
|
|
- word = word[1] unless word.nil?
|
||
|
|
- #STDERR.puts "WORD = #{word.inspect}"
|
||
|
|
- case word
|
||
|
|
- when COMMENT_START
|
||
|
|
- return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ]
|
||
|
|
- when XMLDECL_START
|
||
|
|
- #STDERR.puts "XMLDECL"
|
||
|
|
- results = @source.match( XMLDECL_PATTERN, true )[1]
|
||
|
|
- version = VERSION.match( results )
|
||
|
|
- version = version[1] unless version.nil?
|
||
|
|
- encoding = ENCODING.match(results)
|
||
|
|
- encoding = encoding[1] unless encoding.nil?
|
||
|
|
- if need_source_encoding_update?(encoding)
|
||
|
|
- @source.encoding = encoding
|
||
|
|
- end
|
||
|
|
- if encoding.nil? and /\AUTF-16(?:BE|LE)\z/i =~ @source.encoding
|
||
|
|
- encoding = "UTF-16"
|
||
|
|
- end
|
||
|
|
- standalone = STANDALONE.match(results)
|
||
|
|
- standalone = standalone[1] unless standalone.nil?
|
||
|
|
- return [ :xmldecl, version, encoding, standalone ]
|
||
|
|
- when INSTRUCTION_START
|
||
|
|
- return process_instruction
|
||
|
|
- when DOCTYPE_START
|
||
|
|
- base_error_message = "Malformed DOCTYPE"
|
||
|
|
- @source.match(DOCTYPE_START, true)
|
||
|
|
- @nsstack.unshift(curr_ns=Set.new)
|
||
|
|
- name = parse_name(base_error_message)
|
||
|
|
- if @source.match(/\A\s*\[/um, true)
|
||
|
|
- id = [nil, nil, nil]
|
||
|
|
- @document_status = :in_doctype
|
||
|
|
- elsif @source.match(/\A\s*>/um, true)
|
||
|
|
- id = [nil, nil, nil]
|
||
|
|
- @document_status = :after_doctype
|
||
|
|
- else
|
||
|
|
- id = parse_id(base_error_message,
|
||
|
|
- accept_external_id: true,
|
||
|
|
- accept_public_id: false)
|
||
|
|
- if id[0] == "SYSTEM"
|
||
|
|
- # For backward compatibility
|
||
|
|
- id[1], id[2] = id[2], nil
|
||
|
|
+ start_position = @source.position
|
||
|
|
+ if @source.match("<?", true)
|
||
|
|
+ return process_instruction(start_position)
|
||
|
|
+ elsif @source.match("<!", true)
|
||
|
|
+ if @source.match("--", true)
|
||
|
|
+ md = @source.match(/(.*?)-->/um, true)
|
||
|
|
+ if md.nil?
|
||
|
|
+ raise REXML::ParseException.new("Unclosed comment", @source)
|
||
|
|
+ end
|
||
|
|
+ if /--|-\z/.match?(md[1])
|
||
|
|
+ raise REXML::ParseException.new("Malformed comment", @source)
|
||
|
|
end
|
||
|
|
- if @source.match(/\A\s*\[/um, true)
|
||
|
|
+ return [ :comment, md[1] ]
|
||
|
|
+ elsif @source.match("DOCTYPE", true)
|
||
|
|
+ base_error_message = "Malformed DOCTYPE"
|
||
|
|
+ unless @source.match(/\s+/um, true)
|
||
|
|
+ if @source.match(">")
|
||
|
|
+ message = "#{base_error_message}: name is missing"
|
||
|
|
+ else
|
||
|
|
+ message = "#{base_error_message}: invalid name"
|
||
|
|
+ end
|
||
|
|
+ @source.position = start_position
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
+ end
|
||
|
|
+ @nsstack.unshift(Set.new)
|
||
|
|
+ name = parse_name(base_error_message)
|
||
|
|
+ if @source.match(/\s*\[/um, true)
|
||
|
|
+ id = [nil, nil, nil]
|
||
|
|
@document_status = :in_doctype
|
||
|
|
- elsif @source.match(/\A\s*>/um, true)
|
||
|
|
+ elsif @source.match(/\s*>/um, true)
|
||
|
|
+ id = [nil, nil, nil]
|
||
|
|
@document_status = :after_doctype
|
||
|
|
+ @source.ensure_buffer
|
||
|
|
else
|
||
|
|
- message = "#{base_error_message}: garbage after external ID"
|
||
|
|
- raise REXML::ParseException.new(message, @source)
|
||
|
|
+ id = parse_id(base_error_message,
|
||
|
|
+ accept_external_id: true,
|
||
|
|
+ accept_public_id: false)
|
||
|
|
+ if id[0] == "SYSTEM"
|
||
|
|
+ # For backward compatibility
|
||
|
|
+ id[1], id[2] = id[2], nil
|
||
|
|
+ end
|
||
|
|
+ if @source.match(/\s*\[/um, true)
|
||
|
|
+ @document_status = :in_doctype
|
||
|
|
+ elsif @source.match(/\s*>/um, true)
|
||
|
|
+ @document_status = :after_doctype
|
||
|
|
+ @source.ensure_buffer
|
||
|
|
+ else
|
||
|
|
+ message = "#{base_error_message}: garbage after external ID"
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
- end
|
||
|
|
- args = [:start_doctype, name, *id]
|
||
|
|
- if @document_status == :after_doctype
|
||
|
|
- @source.match(/\A\s*/um, true)
|
||
|
|
- @stack << [ :end_doctype ]
|
||
|
|
- end
|
||
|
|
- return args
|
||
|
|
- when /\A\s+/
|
||
|
|
- else
|
||
|
|
- @document_status = :after_doctype
|
||
|
|
- if @source.encoding == "UTF-8"
|
||
|
|
- @source.buffer.force_encoding(::Encoding::UTF_8)
|
||
|
|
+ args = [:start_doctype, name, *id]
|
||
|
|
+ if @document_status == :after_doctype
|
||
|
|
+ @source.match(/\s*/um, true)
|
||
|
|
+ @stack << [ :end_doctype ]
|
||
|
|
+ end
|
||
|
|
+ return args
|
||
|
|
+ else
|
||
|
|
+ message = "Invalid XML"
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if @document_status == :in_doctype
|
||
|
|
- md = @source.match(/\A\s*(.*?>)/um)
|
||
|
|
- case md[1]
|
||
|
|
- when SYSTEMENTITY
|
||
|
|
- match = @source.match( SYSTEMENTITY, true )[1]
|
||
|
|
- return [ :externalentity, match ]
|
||
|
|
-
|
||
|
|
- when ELEMENTDECL_START
|
||
|
|
- return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ]
|
||
|
|
-
|
||
|
|
- when ENTITY_START
|
||
|
|
- match = @source.match( ENTITYDECL, true ).to_a.compact
|
||
|
|
- match[0] = :entitydecl
|
||
|
|
- ref = false
|
||
|
|
- if match[1] == '%'
|
||
|
|
- ref = true
|
||
|
|
- match.delete_at 1
|
||
|
|
- end
|
||
|
|
- # Now we have to sort out what kind of entity reference this is
|
||
|
|
- if match[2] == 'SYSTEM'
|
||
|
|
- # External reference
|
||
|
|
- match[3] = match[3][1..-2] # PUBID
|
||
|
|
- match.delete_at(4) if match.size > 4 # Chop out NDATA decl
|
||
|
|
- # match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
|
||
|
|
- elsif match[2] == 'PUBLIC'
|
||
|
|
- # External reference
|
||
|
|
- match[3] = match[3][1..-2] # PUBID
|
||
|
|
- match[4] = match[4][1..-2] # HREF
|
||
|
|
- match.delete_at(5) if match.size > 5 # Chop out NDATA decl
|
||
|
|
- # match is [ :entity, name, PUBLIC, pubid, href(, ndata)? ]
|
||
|
|
- else
|
||
|
|
- match[2] = match[2][1..-2]
|
||
|
|
- match.pop if match.size == 4
|
||
|
|
- # match is [ :entity, name, value ]
|
||
|
|
- end
|
||
|
|
- match << '%' if ref
|
||
|
|
- return match
|
||
|
|
- when ATTLISTDECL_START
|
||
|
|
- md = @source.match( ATTLISTDECL_PATTERN, true )
|
||
|
|
- raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
|
||
|
|
- element = md[1]
|
||
|
|
- contents = md[0]
|
||
|
|
-
|
||
|
|
- pairs = {}
|
||
|
|
- values = md[0].scan( ATTDEF_RE )
|
||
|
|
- values.each do |attdef|
|
||
|
|
- unless attdef[3] == "#IMPLIED"
|
||
|
|
- attdef.compact!
|
||
|
|
- val = attdef[3]
|
||
|
|
- val = attdef[4] if val == "#FIXED "
|
||
|
|
- pairs[attdef[0]] = val
|
||
|
|
- if attdef[0] =~ /^xmlns:(.*)/
|
||
|
|
- @nsstack[0] << $1
|
||
|
|
- end
|
||
|
|
+ @source.match(/\s*/um, true) # skip spaces
|
||
|
|
+ start_position = @source.position
|
||
|
|
+ if @source.match("<!", true)
|
||
|
|
+ if @source.match("ELEMENT", true)
|
||
|
|
+ md = @source.match(/(.*?)>/um, true)
|
||
|
|
+ raise REXML::ParseException.new( "Bad ELEMENT declaration!", @source ) if md.nil?
|
||
|
|
+ return [ :elementdecl, "<!ELEMENT" + md[1] ]
|
||
|
|
+ elsif @source.match("ENTITY", true)
|
||
|
|
+ match = [:entitydecl, *@source.match(Private::ENTITYDECL_PATTERN, true).captures.compact]
|
||
|
|
+ ref = false
|
||
|
|
+ if match[1] == '%'
|
||
|
|
+ ref = true
|
||
|
|
+ match.delete_at 1
|
||
|
|
end
|
||
|
|
- end
|
||
|
|
- return [ :attlistdecl, element, pairs, contents ]
|
||
|
|
- when NOTATIONDECL_START
|
||
|
|
- base_error_message = "Malformed notation declaration"
|
||
|
|
- unless @source.match(/\A\s*<!NOTATION\s+/um, true)
|
||
|
|
- if @source.match(/\A\s*<!NOTATION\s*>/um)
|
||
|
|
- message = "#{base_error_message}: name is missing"
|
||
|
|
+ # Now we have to sort out what kind of entity reference this is
|
||
|
|
+ if match[2] == 'SYSTEM'
|
||
|
|
+ # External reference
|
||
|
|
+ match[3] = match[3][1..-2] # PUBID
|
||
|
|
+ match.delete_at(4) if match.size > 4 # Chop out NDATA decl
|
||
|
|
+ # match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
|
||
|
|
+ elsif match[2] == 'PUBLIC'
|
||
|
|
+ # External reference
|
||
|
|
+ match[3] = match[3][1..-2] # PUBID
|
||
|
|
+ match[4] = match[4][1..-2] # HREF
|
||
|
|
+ match.delete_at(5) if match.size > 5 # Chop out NDATA decl
|
||
|
|
+ # match is [ :entity, name, PUBLIC, pubid, href(, ndata)? ]
|
||
|
|
else
|
||
|
|
- message = "#{base_error_message}: invalid declaration name"
|
||
|
|
+ match[2] = match[2][1..-2]
|
||
|
|
+ match.pop if match.size == 4
|
||
|
|
+ # match is [ :entity, name, value ]
|
||
|
|
end
|
||
|
|
- raise REXML::ParseException.new(message, @source)
|
||
|
|
- end
|
||
|
|
- name = parse_name(base_error_message)
|
||
|
|
- id = parse_id(base_error_message,
|
||
|
|
- accept_external_id: true,
|
||
|
|
- accept_public_id: true)
|
||
|
|
- unless @source.match(/\A\s*>/um, true)
|
||
|
|
- message = "#{base_error_message}: garbage before end >"
|
||
|
|
- raise REXML::ParseException.new(message, @source)
|
||
|
|
+ match << '%' if ref
|
||
|
|
+ return match
|
||
|
|
+ elsif @source.match("ATTLIST", true)
|
||
|
|
+ md = @source.match(Private::ATTLISTDECL_END, true)
|
||
|
|
+ raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
|
||
|
|
+ element = md[1]
|
||
|
|
+ contents = md[0]
|
||
|
|
+
|
||
|
|
+ pairs = {}
|
||
|
|
+ values = md[0].scan( ATTDEF_RE )
|
||
|
|
+ values.each do |attdef|
|
||
|
|
+ unless attdef[3] == "#IMPLIED"
|
||
|
|
+ attdef.compact!
|
||
|
|
+ val = attdef[3]
|
||
|
|
+ val = attdef[4] if val == "#FIXED "
|
||
|
|
+ pairs[attdef[0]] = val
|
||
|
|
+ if attdef[0] =~ /^xmlns:(.*)/
|
||
|
|
+ @nsstack[0] << $1
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ return [ :attlistdecl, element, pairs, contents ]
|
||
|
|
+ elsif @source.match("NOTATION", true)
|
||
|
|
+ base_error_message = "Malformed notation declaration"
|
||
|
|
+ unless @source.match(/\s+/um, true)
|
||
|
|
+ if @source.match(">")
|
||
|
|
+ message = "#{base_error_message}: name is missing"
|
||
|
|
+ else
|
||
|
|
+ message = "#{base_error_message}: invalid name"
|
||
|
|
+ end
|
||
|
|
+ @source.position = start_position
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
+ end
|
||
|
|
+ name = parse_name(base_error_message)
|
||
|
|
+ id = parse_id(base_error_message,
|
||
|
|
+ accept_external_id: true,
|
||
|
|
+ accept_public_id: true)
|
||
|
|
+ unless @source.match(/\s*>/um, true)
|
||
|
|
+ message = "#{base_error_message}: garbage before end >"
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
+ end
|
||
|
|
+ return [:notationdecl, name, *id]
|
||
|
|
+ elsif md = @source.match(/--(.*?)-->/um, true)
|
||
|
|
+ case md[1]
|
||
|
|
+ when /--/, /-\z/
|
||
|
|
+ raise REXML::ParseException.new("Malformed comment", @source)
|
||
|
|
+ end
|
||
|
|
+ return [ :comment, md[1] ] if md
|
||
|
|
end
|
||
|
|
- return [:notationdecl, name, *id]
|
||
|
|
- when DOCTYPE_END
|
||
|
|
+ elsif match = @source.match(/(%.*?;)\s*/um, true)
|
||
|
|
+ return [ :externalentity, match[1] ]
|
||
|
|
+ elsif @source.match(/\]\s*>/um, true)
|
||
|
|
@document_status = :after_doctype
|
||
|
|
- @source.match( DOCTYPE_END, true )
|
||
|
|
return [ :end_doctype ]
|
||
|
|
end
|
||
|
|
+ if @document_status == :in_doctype
|
||
|
|
+ raise ParseException.new("Malformed DOCTYPE: invalid declaration", @source)
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
if @document_status == :after_doctype
|
||
|
|
- @source.match(/\A\s*/um, true)
|
||
|
|
+ @source.match(/\s*/um, true)
|
||
|
|
end
|
||
|
|
begin
|
||
|
|
- @source.read if @source.buffer.size<2
|
||
|
|
- if @source.buffer[0] == ?<
|
||
|
|
- if @source.buffer[1] == ?/
|
||
|
|
+ start_position = @source.position
|
||
|
|
+ if @source.match("<", true)
|
||
|
|
+ # :text's read_until may remain only "<" in buffer. In the
|
||
|
|
+ # case, buffer is empty here. So we need to fill buffer
|
||
|
|
+ # here explicitly.
|
||
|
|
+ @source.ensure_buffer
|
||
|
|
+ if @source.match("/", true)
|
||
|
|
@nsstack.shift
|
||
|
|
last_tag = @tags.pop
|
||
|
|
- md = @source.match( CLOSE_MATCH, true )
|
||
|
|
+ md = @source.match(Private::CLOSE_PATTERN, true)
|
||
|
|
if md and !last_tag
|
||
|
|
message = "Unexpected top-level end tag (got '#{md[1]}')"
|
||
|
|
raise REXML::ParseException.new(message, @source)
|
||
|
|
end
|
||
|
|
if md.nil? or last_tag != md[1]
|
||
|
|
message = "Missing end tag for '#{last_tag}'"
|
||
|
|
- message << " (got '#{md[1]}')" if md
|
||
|
|
+ message += " (got '#{md[1]}')" if md
|
||
|
|
+ @source.position = start_position if md.nil?
|
||
|
|
raise REXML::ParseException.new(message, @source)
|
||
|
|
end
|
||
|
|
return [ :end_element, last_tag ]
|
||
|
|
- elsif @source.buffer[1] == ?!
|
||
|
|
- md = @source.match(/\A(\s*[^>]*>)/um)
|
||
|
|
+ elsif @source.match("!", true)
|
||
|
|
+ md = @source.match(/([^>]*>)/um)
|
||
|
|
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
|
||
|
|
raise REXML::ParseException.new("Malformed node", @source) unless md
|
||
|
|
- if md[0][2] == ?-
|
||
|
|
- md = @source.match( COMMENT_PATTERN, true )
|
||
|
|
+ if md[0][0] == ?-
|
||
|
|
+ md = @source.match(/--(.*?)-->/um, true)
|
||
|
|
|
||
|
|
- case md[1]
|
||
|
|
- when /--/, /-\z/
|
||
|
|
+ if md.nil? || /--|-\z/.match?(md[1])
|
||
|
|
raise REXML::ParseException.new("Malformed comment", @source)
|
||
|
|
end
|
||
|
|
|
||
|
|
- return [ :comment, md[1] ] if md
|
||
|
|
+ return [ :comment, md[1] ]
|
||
|
|
else
|
||
|
|
- md = @source.match( CDATA_PATTERN, true )
|
||
|
|
+ md = @source.match(/\[CDATA\[(.*?)\]\]>/um, true)
|
||
|
|
return [ :cdata, md[1] ] if md
|
||
|
|
end
|
||
|
|
raise REXML::ParseException.new( "Declarations can only occur "+
|
||
|
|
"in the doctype declaration.", @source)
|
||
|
|
- elsif @source.buffer[1] == ??
|
||
|
|
- return process_instruction
|
||
|
|
+ elsif @source.match("?", true)
|
||
|
|
+ return process_instruction(start_position)
|
||
|
|
else
|
||
|
|
# Get the next tag
|
||
|
|
- md = @source.match(TAG_MATCH, true)
|
||
|
|
+ md = @source.match(Private::TAG_PATTERN, true)
|
||
|
|
unless md
|
||
|
|
+ @source.position = start_position
|
||
|
|
raise REXML::ParseException.new("malformed XML: missing tag start", @source)
|
||
|
|
end
|
||
|
|
+ tag = md[1]
|
||
|
|
@document_status = :in_element
|
||
|
|
- prefixes = Set.new
|
||
|
|
- prefixes << md[2] if md[2]
|
||
|
|
+ @prefixes.clear
|
||
|
|
+ @prefixes << md[2] if md[2]
|
||
|
|
@nsstack.unshift(curr_ns=Set.new)
|
||
|
|
- attributes, closed = parse_attributes(prefixes, curr_ns)
|
||
|
|
+ attributes, closed = parse_attributes(@prefixes, curr_ns)
|
||
|
|
# Verify that all of the prefixes have been defined
|
||
|
|
- for prefix in prefixes
|
||
|
|
+ for prefix in @prefixes
|
||
|
|
unless @nsstack.find{|k| k.member?(prefix)}
|
||
|
|
raise UndefinedNamespaceException.new(prefix,@source,self)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if closed
|
||
|
|
- @closed = md[1]
|
||
|
|
+ @closed = tag
|
||
|
|
@nsstack.shift
|
||
|
|
else
|
||
|
|
- @tags.push( md[1] )
|
||
|
|
+ @tags.push( tag )
|
||
|
|
end
|
||
|
|
- return [ :start_element, md[1], attributes ]
|
||
|
|
+ return [ :start_element, tag, attributes ]
|
||
|
|
end
|
||
|
|
else
|
||
|
|
- md = @source.match( TEXT_PATTERN, true )
|
||
|
|
- if md[0].length == 0
|
||
|
|
- @source.match( /(\s+)/, true )
|
||
|
|
+ text = @source.read_until("<")
|
||
|
|
+ if text.chomp!("<")
|
||
|
|
+ @source.position -= "<".bytesize
|
||
|
|
end
|
||
|
|
- #STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0
|
||
|
|
- #return [ :text, "" ] if md[0].length == 0
|
||
|
|
- # unnormalized = Text::unnormalize( md[1], self )
|
||
|
|
- # return PullEvent.new( :text, md[1], unnormalized )
|
||
|
|
- return [ :text, md[1] ]
|
||
|
|
+ return [ :text, text ]
|
||
|
|
end
|
||
|
|
rescue REXML::UndefinedNamespaceException
|
||
|
|
raise
|
||
|
|
@@ -463,11 +511,10 @@ module REXML
|
||
|
|
|
||
|
|
# Unescapes all possible entities
|
||
|
|
def unnormalize( string, entities=nil, filter=nil )
|
||
|
|
- rv = string.clone
|
||
|
|
- rv.gsub!( /\r\n?/, "\n" )
|
||
|
|
+ rv = string.gsub( Private::CARRIAGE_RETURN_NEWLINE_PATTERN, "\n" )
|
||
|
|
matches = rv.scan( REFERENCE_RE )
|
||
|
|
return rv if matches.size == 0
|
||
|
|
- rv.gsub!( /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {
|
||
|
|
+ rv.gsub!( Private::CHARACTER_REFERENCES ) {
|
||
|
|
m=$1
|
||
|
|
m = "0#{m}" if m[0] == ?x
|
||
|
|
[Integer(m)].pack('U*')
|
||
|
|
@@ -478,7 +525,7 @@ module REXML
|
||
|
|
unless filter and filter.include?(entity_reference)
|
||
|
|
entity_value = entity( entity_reference, entities )
|
||
|
|
if entity_value
|
||
|
|
- re = /&#{entity_reference};/
|
||
|
|
+ re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
|
||
|
|
rv.gsub!( re, entity_value )
|
||
|
|
else
|
||
|
|
er = DEFAULT_ENTITIES[entity_reference]
|
||
|
|
@@ -486,7 +533,7 @@ module REXML
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
- rv.gsub!( /&/, '&' )
|
||
|
|
+ rv.gsub!( Private::DEFAULT_ENTITIES_PATTERNS['amp'], '&' )
|
||
|
|
end
|
||
|
|
rv
|
||
|
|
end
|
||
|
|
@@ -499,9 +546,9 @@ module REXML
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse_name(base_error_message)
|
||
|
|
- md = @source.match(/\A\s*#{NAME}/um, true)
|
||
|
|
+ md = @source.match(Private::NAME_PATTERN, true)
|
||
|
|
unless md
|
||
|
|
- if @source.match(/\A\s*\S/um)
|
||
|
|
+ if @source.match(/\s*\S/um)
|
||
|
|
message = "#{base_error_message}: invalid name"
|
||
|
|
else
|
||
|
|
message = "#{base_error_message}: name is missing"
|
||
|
|
@@ -577,97 +624,91 @@ module REXML
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
- def process_instruction
|
||
|
|
- match_data = @source.match(INSTRUCTION_PATTERN, true)
|
||
|
|
+ def process_instruction(start_position)
|
||
|
|
+ match_data = @source.match(Private::INSTRUCTION_END, true)
|
||
|
|
unless match_data
|
||
|
|
message = "Invalid processing instruction node"
|
||
|
|
+ @source.position = start_position
|
||
|
|
raise REXML::ParseException.new(message, @source)
|
||
|
|
end
|
||
|
|
+ if @document_status.nil? and match_data[1] == "xml"
|
||
|
|
+ content = match_data[2]
|
||
|
|
+ version = VERSION.match(content)
|
||
|
|
+ version = version[1] unless version.nil?
|
||
|
|
+ encoding = ENCODING.match(content)
|
||
|
|
+ encoding = encoding[1] unless encoding.nil?
|
||
|
|
+ if need_source_encoding_update?(encoding)
|
||
|
|
+ @source.encoding = encoding
|
||
|
|
+ end
|
||
|
|
+ if encoding.nil? and /\AUTF-16(?:BE|LE)\z/i =~ @source.encoding
|
||
|
|
+ encoding = "UTF-16"
|
||
|
|
+ end
|
||
|
|
+ standalone = STANDALONE.match(content)
|
||
|
|
+ standalone = standalone[1] unless standalone.nil?
|
||
|
|
+ return [ :xmldecl, version, encoding, standalone ]
|
||
|
|
+ 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)
|
||
|
|
+ while true
|
||
|
|
+ if @source.match(">", true)
|
||
|
|
+ return attributes, closed
|
||
|
|
+ elsif @source.match("/>", true)
|
||
|
|
+ closed = true
|
||
|
|
+ return attributes, closed
|
||
|
|
+ elsif match = @source.match(QNAME, true)
|
||
|
|
+ name = match[1]
|
||
|
|
+ prefix = match[2]
|
||
|
|
+ local_part = match[3]
|
||
|
|
+
|
||
|
|
+ unless @source.match(/\s*=\s*/um, true)
|
||
|
|
message = "Missing attribute equal: <#{name}>"
|
||
|
|
raise REXML::ParseException.new(message, @source)
|
||
|
|
end
|
||
|
|
- quote = scanner.scan(/['"]/)
|
||
|
|
- unless quote
|
||
|
|
+ unless match = @source.match(/(['"])/, true)
|
||
|
|
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}>"
|
||
|
|
+ quote = match[1]
|
||
|
|
+ start_position = @source.position
|
||
|
|
+ value = @source.read_until(quote)
|
||
|
|
+ unless value.chomp!(quote)
|
||
|
|
+ @source.position = start_position
|
||
|
|
+ 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 "+
|
||
|
|
+ @source.match(/\s*/um, true)
|
||
|
|
+ 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 )
|
||
|
|
+ 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)
|
||
|
|
+ curr_ns << local_part
|
||
|
|
+ elsif prefix
|
||
|
|
+ prefixes << prefix unless prefix == "xml"
|
||
|
|
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
|
||
|
|
+ if attributes[name]
|
||
|
|
+ msg = "Duplicate attribute #{name.inspect}"
|
||
|
|
+ raise REXML::ParseException.new(msg, @source, self)
|
||
|
|
+ end
|
||
|
|
|
||
|
|
- attributes[name] = value
|
||
|
|
+ attributes[name] = value
|
||
|
|
+ else
|
||
|
|
+ message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>"
|
||
|
|
+ raise REXML::ParseException.new(message, @source)
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
- return attributes, closed
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
|
||
|
|
index bf9a425..0cb6f7c 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
|
||
|
|
@@ -16,7 +16,6 @@ module REXML
|
||
|
|
|
||
|
|
def parse
|
||
|
|
tag_stack = []
|
||
|
|
- in_doctype = false
|
||
|
|
entities = nil
|
||
|
|
begin
|
||
|
|
while true
|
||
|
|
@@ -39,17 +38,15 @@ module REXML
|
||
|
|
tag_stack.pop
|
||
|
|
@build_context = @build_context.parent
|
||
|
|
when :text
|
||
|
|
- if not in_doctype
|
||
|
|
- if @build_context[-1].instance_of? Text
|
||
|
|
- @build_context[-1] << event[1]
|
||
|
|
- else
|
||
|
|
- @build_context.add(
|
||
|
|
- Text.new(event[1], @build_context.whitespace, nil, true)
|
||
|
|
- ) unless (
|
||
|
|
- @build_context.ignore_whitespace_nodes and
|
||
|
|
- event[1].strip.size==0
|
||
|
|
- )
|
||
|
|
- end
|
||
|
|
+ if @build_context[-1].instance_of? Text
|
||
|
|
+ @build_context[-1] << event[1]
|
||
|
|
+ else
|
||
|
|
+ @build_context.add(
|
||
|
|
+ Text.new(event[1], @build_context.whitespace, nil, true)
|
||
|
|
+ ) unless (
|
||
|
|
+ @build_context.ignore_whitespace_nodes and
|
||
|
|
+ event[1].strip.size==0
|
||
|
|
+ )
|
||
|
|
end
|
||
|
|
when :comment
|
||
|
|
c = Comment.new( event[1] )
|
||
|
|
@@ -60,14 +57,12 @@ module REXML
|
||
|
|
when :processing_instruction
|
||
|
|
@build_context.add( Instruction.new( event[1], event[2] ) )
|
||
|
|
when :end_doctype
|
||
|
|
- in_doctype = false
|
||
|
|
entities.each { |k,v| entities[k] = @build_context.entities[k].value }
|
||
|
|
@build_context = @build_context.parent
|
||
|
|
when :start_doctype
|
||
|
|
doctype = DocType.new( event[1..-1], @build_context )
|
||
|
|
@build_context = doctype
|
||
|
|
entities = {}
|
||
|
|
- in_doctype = true
|
||
|
|
when :attlistdecl
|
||
|
|
n = AttlistDecl.new( event[1..-1] )
|
||
|
|
@build_context.add( n )
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb
|
||
|
|
index d92678f..bd3b685 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb
|
||
|
|
@@ -1,4 +1,5 @@
|
||
|
|
# frozen_string_literal: false
|
||
|
|
+
|
||
|
|
require_relative '../namespace'
|
||
|
|
require_relative '../xmltokens'
|
||
|
|
|
||
|
|
@@ -38,108 +39,143 @@ module REXML
|
||
|
|
parsed
|
||
|
|
end
|
||
|
|
|
||
|
|
- def abbreviate( path )
|
||
|
|
- path = path.kind_of?(String) ? parse( path ) : path
|
||
|
|
- string = ""
|
||
|
|
- document = false
|
||
|
|
- while path.size > 0
|
||
|
|
- op = path.shift
|
||
|
|
+ def abbreviate(path_or_parsed)
|
||
|
|
+ if path_or_parsed.kind_of?(String)
|
||
|
|
+ parsed = parse(path_or_parsed)
|
||
|
|
+ else
|
||
|
|
+ parsed = path_or_parsed
|
||
|
|
+ end
|
||
|
|
+ components = []
|
||
|
|
+ component = nil
|
||
|
|
+ while parsed.size > 0
|
||
|
|
+ op = parsed.shift
|
||
|
|
case op
|
||
|
|
when :node
|
||
|
|
+ component << "node()"
|
||
|
|
when :attribute
|
||
|
|
- string << "/" if string.size > 0
|
||
|
|
- string << "@"
|
||
|
|
+ component = "@"
|
||
|
|
+ components << component
|
||
|
|
when :child
|
||
|
|
- string << "/" if string.size > 0
|
||
|
|
+ component = ""
|
||
|
|
+ components << component
|
||
|
|
when :descendant_or_self
|
||
|
|
- string << "/"
|
||
|
|
+ next_op = parsed[0]
|
||
|
|
+ if next_op == :node
|
||
|
|
+ parsed.shift
|
||
|
|
+ component = ""
|
||
|
|
+ components << component
|
||
|
|
+ else
|
||
|
|
+ component = "descendant-or-self::"
|
||
|
|
+ components << component
|
||
|
|
+ end
|
||
|
|
when :self
|
||
|
|
- string << "."
|
||
|
|
+ next_op = parsed[0]
|
||
|
|
+ if next_op == :node
|
||
|
|
+ parsed.shift
|
||
|
|
+ components << "."
|
||
|
|
+ else
|
||
|
|
+ component = "self::"
|
||
|
|
+ components << component
|
||
|
|
+ end
|
||
|
|
when :parent
|
||
|
|
- string << ".."
|
||
|
|
+ next_op = parsed[0]
|
||
|
|
+ if next_op == :node
|
||
|
|
+ parsed.shift
|
||
|
|
+ components << ".."
|
||
|
|
+ else
|
||
|
|
+ component = "parent::"
|
||
|
|
+ components << component
|
||
|
|
+ end
|
||
|
|
when :any
|
||
|
|
- string << "*"
|
||
|
|
+ component << "*"
|
||
|
|
when :text
|
||
|
|
- string << "text()"
|
||
|
|
+ component << "text()"
|
||
|
|
when :following, :following_sibling,
|
||
|
|
:ancestor, :ancestor_or_self, :descendant,
|
||
|
|
:namespace, :preceding, :preceding_sibling
|
||
|
|
- string << "/" unless string.size == 0
|
||
|
|
- string << op.to_s.tr("_", "-")
|
||
|
|
- string << "::"
|
||
|
|
+ component = op.to_s.tr("_", "-") << "::"
|
||
|
|
+ components << component
|
||
|
|
when :qname
|
||
|
|
- prefix = path.shift
|
||
|
|
- name = path.shift
|
||
|
|
- string << prefix+":" if prefix.size > 0
|
||
|
|
- string << name
|
||
|
|
+ prefix = parsed.shift
|
||
|
|
+ name = parsed.shift
|
||
|
|
+ component << prefix+":" if prefix.size > 0
|
||
|
|
+ component << name
|
||
|
|
when :predicate
|
||
|
|
- string << '['
|
||
|
|
- string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
|
||
|
|
- string << ']'
|
||
|
|
+ component << '['
|
||
|
|
+ component << predicate_to_path(parsed.shift) {|x| abbreviate(x)}
|
||
|
|
+ component << ']'
|
||
|
|
when :document
|
||
|
|
- document = true
|
||
|
|
+ components << ""
|
||
|
|
when :function
|
||
|
|
- string << path.shift
|
||
|
|
- string << "( "
|
||
|
|
- string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
|
||
|
|
- string << " )"
|
||
|
|
+ component << parsed.shift
|
||
|
|
+ component << "( "
|
||
|
|
+ component << predicate_to_path(parsed.shift[0]) {|x| abbreviate(x)}
|
||
|
|
+ component << " )"
|
||
|
|
when :literal
|
||
|
|
- string << %Q{ "#{path.shift}" }
|
||
|
|
+ component << quote_literal(parsed.shift)
|
||
|
|
else
|
||
|
|
- string << "/" unless string.size == 0
|
||
|
|
- string << "UNKNOWN("
|
||
|
|
- string << op.inspect
|
||
|
|
- string << ")"
|
||
|
|
+ component << "UNKNOWN("
|
||
|
|
+ component << op.inspect
|
||
|
|
+ component << ")"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
- string = "/"+string if document
|
||
|
|
- return string
|
||
|
|
+ case components
|
||
|
|
+ when [""]
|
||
|
|
+ "/"
|
||
|
|
+ when ["", ""]
|
||
|
|
+ "//"
|
||
|
|
+ else
|
||
|
|
+ components.join("/")
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
|
||
|
|
- def expand( path )
|
||
|
|
- path = path.kind_of?(String) ? parse( path ) : path
|
||
|
|
- string = ""
|
||
|
|
+ def expand(path_or_parsed)
|
||
|
|
+ if path_or_parsed.kind_of?(String)
|
||
|
|
+ parsed = parse(path_or_parsed)
|
||
|
|
+ else
|
||
|
|
+ parsed = path_or_parsed
|
||
|
|
+ end
|
||
|
|
+ path = ""
|
||
|
|
document = false
|
||
|
|
- while path.size > 0
|
||
|
|
- op = path.shift
|
||
|
|
+ while parsed.size > 0
|
||
|
|
+ op = parsed.shift
|
||
|
|
case op
|
||
|
|
when :node
|
||
|
|
- string << "node()"
|
||
|
|
+ path << "node()"
|
||
|
|
when :attribute, :child, :following, :following_sibling,
|
||
|
|
:ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
|
||
|
|
:namespace, :preceding, :preceding_sibling, :self, :parent
|
||
|
|
- string << "/" unless string.size == 0
|
||
|
|
- string << op.to_s.tr("_", "-")
|
||
|
|
- string << "::"
|
||
|
|
+ path << "/" unless path.size == 0
|
||
|
|
+ path << op.to_s.tr("_", "-")
|
||
|
|
+ path << "::"
|
||
|
|
when :any
|
||
|
|
- string << "*"
|
||
|
|
+ path << "*"
|
||
|
|
when :qname
|
||
|
|
- prefix = path.shift
|
||
|
|
- name = path.shift
|
||
|
|
- string << prefix+":" if prefix.size > 0
|
||
|
|
- string << name
|
||
|
|
+ prefix = parsed.shift
|
||
|
|
+ name = parsed.shift
|
||
|
|
+ path << prefix+":" if prefix.size > 0
|
||
|
|
+ path << name
|
||
|
|
when :predicate
|
||
|
|
- string << '['
|
||
|
|
- string << predicate_to_string( path.shift ) { |x| expand(x) }
|
||
|
|
- string << ']'
|
||
|
|
+ path << '['
|
||
|
|
+ path << predicate_to_path( parsed.shift ) { |x| expand(x) }
|
||
|
|
+ path << ']'
|
||
|
|
when :document
|
||
|
|
document = true
|
||
|
|
else
|
||
|
|
- string << "/" unless string.size == 0
|
||
|
|
- string << "UNKNOWN("
|
||
|
|
- string << op.inspect
|
||
|
|
- string << ")"
|
||
|
|
+ path << "UNKNOWN("
|
||
|
|
+ path << op.inspect
|
||
|
|
+ path << ")"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
- string = "/"+string if document
|
||
|
|
- return string
|
||
|
|
+ path = "/"+path if document
|
||
|
|
+ path
|
||
|
|
end
|
||
|
|
|
||
|
|
- def predicate_to_string( path, &block )
|
||
|
|
- string = ""
|
||
|
|
- case path[0]
|
||
|
|
+ def predicate_to_path(parsed, &block)
|
||
|
|
+ path = ""
|
||
|
|
+ case parsed[0]
|
||
|
|
when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
|
||
|
|
- op = path.shift
|
||
|
|
+ op = parsed.shift
|
||
|
|
case op
|
||
|
|
when :eq
|
||
|
|
op = "="
|
||
|
|
@@ -156,36 +192,50 @@ module REXML
|
||
|
|
when :union
|
||
|
|
op = "|"
|
||
|
|
end
|
||
|
|
- left = predicate_to_string( path.shift, &block )
|
||
|
|
- right = predicate_to_string( path.shift, &block )
|
||
|
|
- string << " "
|
||
|
|
- string << left
|
||
|
|
- string << " "
|
||
|
|
- string << op.to_s
|
||
|
|
- string << " "
|
||
|
|
- string << right
|
||
|
|
- string << " "
|
||
|
|
+ left = predicate_to_path( parsed.shift, &block )
|
||
|
|
+ right = predicate_to_path( parsed.shift, &block )
|
||
|
|
+ path << left
|
||
|
|
+ path << " "
|
||
|
|
+ path << op.to_s
|
||
|
|
+ path << " "
|
||
|
|
+ path << right
|
||
|
|
when :function
|
||
|
|
- path.shift
|
||
|
|
- name = path.shift
|
||
|
|
- string << name
|
||
|
|
- string << "( "
|
||
|
|
- string << predicate_to_string( path.shift, &block )
|
||
|
|
- string << " )"
|
||
|
|
+ parsed.shift
|
||
|
|
+ name = parsed.shift
|
||
|
|
+ path << name
|
||
|
|
+ path << "("
|
||
|
|
+ parsed.shift.each_with_index do |argument, i|
|
||
|
|
+ path << ", " if i > 0
|
||
|
|
+ path << predicate_to_path(argument, &block)
|
||
|
|
+ end
|
||
|
|
+ path << ")"
|
||
|
|
when :literal
|
||
|
|
- path.shift
|
||
|
|
- string << " "
|
||
|
|
- string << path.shift.inspect
|
||
|
|
- string << " "
|
||
|
|
+ parsed.shift
|
||
|
|
+ path << quote_literal(parsed.shift)
|
||
|
|
else
|
||
|
|
- string << " "
|
||
|
|
- string << yield( path )
|
||
|
|
- string << " "
|
||
|
|
+ path << yield( parsed )
|
||
|
|
end
|
||
|
|
- return string.squeeze(" ")
|
||
|
|
+ return path.squeeze(" ")
|
||
|
|
end
|
||
|
|
+ # For backward compatibility
|
||
|
|
+ alias_method :preciate_to_string, :predicate_to_path
|
||
|
|
|
||
|
|
private
|
||
|
|
+ def quote_literal( literal )
|
||
|
|
+ case literal
|
||
|
|
+ when String
|
||
|
|
+ # XPath 1.0 does not support escape characters.
|
||
|
|
+ # Assumes literal does not contain both single and double quotes.
|
||
|
|
+ if literal.include?("'")
|
||
|
|
+ "\"#{literal}\""
|
||
|
|
+ else
|
||
|
|
+ "'#{literal}'"
|
||
|
|
+ end
|
||
|
|
+ else
|
||
|
|
+ literal.inspect
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
#LocationPath
|
||
|
|
# | RelativeLocationPath
|
||
|
|
# | '/' RelativeLocationPath?
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
|
||
|
|
index 8a01f0e..573d0a1 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
|
||
|
|
@@ -26,10 +26,12 @@
|
||
|
|
# - REXML::Document.
|
||
|
|
# - REXML::Element.
|
||
|
|
#
|
||
|
|
+# There's also an {REXML tutorial}[doc/rexml/tutorial_rdoc.html].
|
||
|
|
+#
|
||
|
|
module REXML
|
||
|
|
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
|
||
|
|
DATE = "2008/019"
|
||
|
|
- VERSION = "3.2.5"
|
||
|
|
+ VERSION = "3.3.1"
|
||
|
|
REVISION = ""
|
||
|
|
|
||
|
|
Copyright = COPYRIGHT
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
|
||
|
|
index 90b370b..5715c35 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
|
||
|
|
@@ -1,8 +1,28 @@
|
||
|
|
# coding: US-ASCII
|
||
|
|
# frozen_string_literal: false
|
||
|
|
+
|
||
|
|
+require "strscan"
|
||
|
|
+
|
||
|
|
require_relative 'encoding'
|
||
|
|
|
||
|
|
module REXML
|
||
|
|
+ if StringScanner::Version < "1.0.0"
|
||
|
|
+ module StringScannerCheckScanString
|
||
|
|
+ refine StringScanner do
|
||
|
|
+ def check(pattern)
|
||
|
|
+ pattern = /#{Regexp.escape(pattern)}/ if pattern.is_a?(String)
|
||
|
|
+ super(pattern)
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ def scan(pattern)
|
||
|
|
+ pattern = /#{Regexp.escape(pattern)}/ if pattern.is_a?(String)
|
||
|
|
+ super(pattern)
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ using StringScannerCheckScanString
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
# Generates Source-s. USE THIS CLASS.
|
||
|
|
class SourceFactory
|
||
|
|
# Generates a Source object
|
||
|
|
@@ -30,18 +50,27 @@ module REXML
|
||
|
|
# objects and provides consumption of text
|
||
|
|
class Source
|
||
|
|
include Encoding
|
||
|
|
- # The current buffer (what we're going to read next)
|
||
|
|
- attr_reader :buffer
|
||
|
|
# The line number of the last consumed text
|
||
|
|
attr_reader :line
|
||
|
|
attr_reader :encoding
|
||
|
|
|
||
|
|
+ module Private
|
||
|
|
+ SCANNER_RESET_SIZE = 100000
|
||
|
|
+ PRE_DEFINED_TERM_PATTERNS = {}
|
||
|
|
+ pre_defined_terms = ["'", '"', "<"]
|
||
|
|
+ pre_defined_terms.each do |term|
|
||
|
|
+ PRE_DEFINED_TERM_PATTERNS[term] = /#{Regexp.escape(term)}/
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+ private_constant :Private
|
||
|
|
+
|
||
|
|
# Constructor
|
||
|
|
# @param arg must be a String, and should be a valid XML document
|
||
|
|
# @param encoding if non-null, sets the encoding of the source to this
|
||
|
|
# value, overriding all encoding detection
|
||
|
|
def initialize(arg, encoding=nil)
|
||
|
|
- @orig = @buffer = arg
|
||
|
|
+ @orig = arg
|
||
|
|
+ @scanner = StringScanner.new(@orig)
|
||
|
|
if encoding
|
||
|
|
self.encoding = encoding
|
||
|
|
else
|
||
|
|
@@ -50,6 +79,20 @@ module REXML
|
||
|
|
@line = 0
|
||
|
|
end
|
||
|
|
|
||
|
|
+ # The current buffer (what we're going to read next)
|
||
|
|
+ def buffer
|
||
|
|
+ @scanner.rest
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ def drop_parsed_content
|
||
|
|
+ if @scanner.pos > Private::SCANNER_RESET_SIZE
|
||
|
|
+ @scanner.string = @scanner.rest
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ def buffer_encoding=(encoding)
|
||
|
|
+ @scanner.string.force_encoding(encoding)
|
||
|
|
+ end
|
||
|
|
|
||
|
|
# Inherited from Encoding
|
||
|
|
# Overridden to support optimized en/decoding
|
||
|
|
@@ -58,98 +101,78 @@ module REXML
|
||
|
|
encoding_updated
|
||
|
|
end
|
||
|
|
|
||
|
|
- # Scans the source for a given pattern. Note, that this is not your
|
||
|
|
- # usual scan() method. For one thing, the pattern argument has some
|
||
|
|
- # requirements; for another, the source can be consumed. You can easily
|
||
|
|
- # confuse this method. Originally, the patterns were easier
|
||
|
|
- # to construct and this method more robust, because this method
|
||
|
|
- # generated search regexps on the fly; however, this was
|
||
|
|
- # computationally expensive and slowed down the entire REXML package
|
||
|
|
- # considerably, since this is by far the most commonly called method.
|
||
|
|
- # @param pattern must be a Regexp, and must be in the form of
|
||
|
|
- # /^\s*(#{your pattern, with no groups})(.*)/. The first group
|
||
|
|
- # will be returned; the second group is used if the consume flag is
|
||
|
|
- # set.
|
||
|
|
- # @param consume if true, the pattern returned will be consumed, leaving
|
||
|
|
- # everything after it in the Source.
|
||
|
|
- # @return the pattern, if found, or nil if the Source is empty or the
|
||
|
|
- # pattern is not found.
|
||
|
|
- def scan(pattern, cons=false)
|
||
|
|
- return nil if @buffer.nil?
|
||
|
|
- rv = @buffer.scan(pattern)
|
||
|
|
- @buffer = $' if cons and rv.size>0
|
||
|
|
- rv
|
||
|
|
+ def read(term = nil)
|
||
|
|
end
|
||
|
|
|
||
|
|
- def read
|
||
|
|
+ def read_until(term)
|
||
|
|
+ pattern = Private::PRE_DEFINED_TERM_PATTERNS[term] || /#{Regexp.escape(term)}/
|
||
|
|
+ data = @scanner.scan_until(pattern)
|
||
|
|
+ unless data
|
||
|
|
+ data = @scanner.rest
|
||
|
|
+ @scanner.pos = @scanner.string.bytesize
|
||
|
|
+ end
|
||
|
|
+ data
|
||
|
|
end
|
||
|
|
|
||
|
|
- def consume( pattern )
|
||
|
|
- @buffer = $' if pattern.match( @buffer )
|
||
|
|
+ def ensure_buffer
|
||
|
|
end
|
||
|
|
|
||
|
|
- def match_to( char, pattern )
|
||
|
|
- return pattern.match(@buffer)
|
||
|
|
+ def match(pattern, cons=false)
|
||
|
|
+ if cons
|
||
|
|
+ @scanner.scan(pattern).nil? ? nil : @scanner
|
||
|
|
+ else
|
||
|
|
+ @scanner.check(pattern).nil? ? nil : @scanner
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
|
||
|
|
- def match_to_consume( char, pattern )
|
||
|
|
- md = pattern.match(@buffer)
|
||
|
|
- @buffer = $'
|
||
|
|
- return md
|
||
|
|
+ def position
|
||
|
|
+ @scanner.pos
|
||
|
|
end
|
||
|
|
|
||
|
|
- def match(pattern, cons=false)
|
||
|
|
- md = pattern.match(@buffer)
|
||
|
|
- @buffer = $' if cons and md
|
||
|
|
- return md
|
||
|
|
+ def position=(pos)
|
||
|
|
+ @scanner.pos = pos
|
||
|
|
end
|
||
|
|
|
||
|
|
# @return true if the Source is exhausted
|
||
|
|
def empty?
|
||
|
|
- @buffer == ""
|
||
|
|
- end
|
||
|
|
-
|
||
|
|
- def position
|
||
|
|
- @orig.index( @buffer )
|
||
|
|
+ @scanner.eos?
|
||
|
|
end
|
||
|
|
|
||
|
|
# @return the current line in the source
|
||
|
|
def current_line
|
||
|
|
lines = @orig.split
|
||
|
|
- res = lines.grep @buffer[0..30]
|
||
|
|
+ res = lines.grep @scanner.rest[0..30]
|
||
|
|
res = res[-1] if res.kind_of? Array
|
||
|
|
lines.index( res ) if res
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
+
|
||
|
|
def detect_encoding
|
||
|
|
- buffer_encoding = @buffer.encoding
|
||
|
|
+ scanner_encoding = @scanner.rest.encoding
|
||
|
|
detected_encoding = "UTF-8"
|
||
|
|
begin
|
||
|
|
- @buffer.force_encoding("ASCII-8BIT")
|
||
|
|
- if @buffer[0, 2] == "\xfe\xff"
|
||
|
|
- @buffer[0, 2] = ""
|
||
|
|
+ @scanner.string.force_encoding("ASCII-8BIT")
|
||
|
|
+ if @scanner.scan(/\xfe\xff/n)
|
||
|
|
detected_encoding = "UTF-16BE"
|
||
|
|
- elsif @buffer[0, 2] == "\xff\xfe"
|
||
|
|
- @buffer[0, 2] = ""
|
||
|
|
+ elsif @scanner.scan(/\xff\xfe/n)
|
||
|
|
detected_encoding = "UTF-16LE"
|
||
|
|
- elsif @buffer[0, 3] == "\xef\xbb\xbf"
|
||
|
|
- @buffer[0, 3] = ""
|
||
|
|
+ elsif @scanner.scan(/\xef\xbb\xbf/n)
|
||
|
|
detected_encoding = "UTF-8"
|
||
|
|
end
|
||
|
|
ensure
|
||
|
|
- @buffer.force_encoding(buffer_encoding)
|
||
|
|
+ @scanner.string.force_encoding(scanner_encoding)
|
||
|
|
end
|
||
|
|
self.encoding = detected_encoding
|
||
|
|
end
|
||
|
|
|
||
|
|
def encoding_updated
|
||
|
|
if @encoding != 'UTF-8'
|
||
|
|
- @buffer = decode(@buffer)
|
||
|
|
+ @scanner.string = decode(@scanner.rest)
|
||
|
|
@to_utf = true
|
||
|
|
else
|
||
|
|
@to_utf = false
|
||
|
|
- @buffer.force_encoding ::Encoding::UTF_8
|
||
|
|
+ @scanner.string.force_encoding(::Encoding::UTF_8)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
@@ -172,7 +195,7 @@ module REXML
|
||
|
|
end
|
||
|
|
|
||
|
|
if !@to_utf and
|
||
|
|
- @buffer.respond_to?(:force_encoding) and
|
||
|
|
+ @orig.respond_to?(:force_encoding) and
|
||
|
|
@source.respond_to?(:external_encoding) and
|
||
|
|
@source.external_encoding != ::Encoding::UTF_8
|
||
|
|
@force_utf8 = true
|
||
|
|
@@ -181,65 +204,62 @@ module REXML
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
- def scan(pattern, cons=false)
|
||
|
|
- rv = super
|
||
|
|
- # You'll notice that this next section is very similar to the same
|
||
|
|
- # section in match(), but just a liiittle different. This is
|
||
|
|
- # because it is a touch faster to do it this way with scan()
|
||
|
|
- # than the way match() does it; enough faster to warrant duplicating
|
||
|
|
- # some code
|
||
|
|
- if rv.size == 0
|
||
|
|
- until @buffer =~ pattern or @source.nil?
|
||
|
|
- begin
|
||
|
|
- @buffer << readline
|
||
|
|
- rescue Iconv::IllegalSequence
|
||
|
|
- raise
|
||
|
|
- rescue
|
||
|
|
- @source = nil
|
||
|
|
- end
|
||
|
|
- end
|
||
|
|
- rv = super
|
||
|
|
- end
|
||
|
|
- rv.taint if RUBY_VERSION < '2.7'
|
||
|
|
- rv
|
||
|
|
- end
|
||
|
|
-
|
||
|
|
- def read
|
||
|
|
+ def read(term = nil)
|
||
|
|
+ term = encode(term) if term
|
||
|
|
begin
|
||
|
|
- @buffer << readline
|
||
|
|
+ @scanner << readline(term)
|
||
|
|
+ true
|
||
|
|
rescue Exception, NameError
|
||
|
|
@source = nil
|
||
|
|
+ false
|
||
|
|
+ end
|
||
|
|
+ end
|
||
|
|
+
|
||
|
|
+ def read_until(term)
|
||
|
|
+ pattern = Private::PRE_DEFINED_TERM_PATTERNS[term] || /#{Regexp.escape(term)}/
|
||
|
|
+ term = encode(term)
|
||
|
|
+ until str = @scanner.scan_until(pattern)
|
||
|
|
+ break if @source.nil?
|
||
|
|
+ break if @source.eof?
|
||
|
|
+ @scanner << readline(term)
|
||
|
|
+ end
|
||
|
|
+ if str
|
||
|
|
+ read if @scanner.eos? and !@source.eof?
|
||
|
|
+ str
|
||
|
|
+ else
|
||
|
|
+ rest = @scanner.rest
|
||
|
|
+ @scanner.pos = @scanner.string.bytesize
|
||
|
|
+ rest
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
- def consume( pattern )
|
||
|
|
- match( pattern, true )
|
||
|
|
+ def ensure_buffer
|
||
|
|
+ read if @scanner.eos? && @source
|
||
|
|
end
|
||
|
|
|
||
|
|
+ # Note: When specifying a string for 'pattern', it must not include '>' except in the following formats:
|
||
|
|
+ # - ">"
|
||
|
|
+ # - "XXX>" (X is any string excluding '>')
|
||
|
|
def match( pattern, cons=false )
|
||
|
|
- rv = pattern.match(@buffer)
|
||
|
|
- @buffer = $' if cons and rv
|
||
|
|
- while !rv and @source
|
||
|
|
- begin
|
||
|
|
- @buffer << readline
|
||
|
|
- rv = pattern.match(@buffer)
|
||
|
|
- @buffer = $' if cons and rv
|
||
|
|
- rescue
|
||
|
|
- @source = nil
|
||
|
|
+ while true
|
||
|
|
+ if cons
|
||
|
|
+ md = @scanner.scan(pattern)
|
||
|
|
+ else
|
||
|
|
+ md = @scanner.check(pattern)
|
||
|
|
end
|
||
|
|
+ break if md
|
||
|
|
+ return nil if pattern.is_a?(String)
|
||
|
|
+ return nil if @source.nil?
|
||
|
|
+ return nil unless read
|
||
|
|
end
|
||
|
|
- rv.taint if RUBY_VERSION < '2.7'
|
||
|
|
- rv
|
||
|
|
+
|
||
|
|
+ md.nil? ? nil : @scanner
|
||
|
|
end
|
||
|
|
|
||
|
|
def empty?
|
||
|
|
super and ( @source.nil? || @source.eof? )
|
||
|
|
end
|
||
|
|
|
||
|
|
- def position
|
||
|
|
- @er_source.pos rescue 0
|
||
|
|
- end
|
||
|
|
-
|
||
|
|
# @return the current line in the source
|
||
|
|
def current_line
|
||
|
|
begin
|
||
|
|
@@ -263,8 +283,8 @@ module REXML
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
- def readline
|
||
|
|
- str = @source.readline(@line_break)
|
||
|
|
+ def readline(term = nil)
|
||
|
|
+ str = @source.readline(term || @line_break)
|
||
|
|
if @pending_buffer
|
||
|
|
if str.nil?
|
||
|
|
str = @pending_buffer
|
||
|
|
@@ -290,7 +310,7 @@ module REXML
|
||
|
|
@source.set_encoding(@encoding, @encoding)
|
||
|
|
end
|
||
|
|
@line_break = encode(">")
|
||
|
|
- @pending_buffer, @buffer = @buffer, ""
|
||
|
|
+ @pending_buffer, @scanner.string = @scanner.rest, ""
|
||
|
|
@pending_buffer.force_encoding(@encoding)
|
||
|
|
super
|
||
|
|
end
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/text.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/text.rb
|
||
|
|
index 050b09c..b47bad3 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/text.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/text.rb
|
||
|
|
@@ -1,4 +1,4 @@
|
||
|
|
-# frozen_string_literal: false
|
||
|
|
+# frozen_string_literal: true
|
||
|
|
require_relative 'security'
|
||
|
|
require_relative 'entity'
|
||
|
|
require_relative 'doctype'
|
||
|
|
@@ -131,7 +131,7 @@ module REXML
|
||
|
|
def Text.check string, pattern, doctype
|
||
|
|
|
||
|
|
# illegal anywhere
|
||
|
|
- if string !~ VALID_XML_CHARS
|
||
|
|
+ if !string.match?(VALID_XML_CHARS)
|
||
|
|
if String.method_defined? :encode
|
||
|
|
string.chars.each do |c|
|
||
|
|
case c.ord
|
||
|
|
@@ -371,7 +371,7 @@ module REXML
|
||
|
|
copy = input.to_s
|
||
|
|
# Doing it like this rather than in a loop improves the speed
|
||
|
|
#copy = copy.gsub( EREFERENCE, '&' )
|
||
|
|
- copy = copy.gsub( "&", "&" )
|
||
|
|
+ copy = copy.gsub( "&", "&" ) if copy.include?("&")
|
||
|
|
if doctype
|
||
|
|
# Replace all ampersands that aren't part of an entity
|
||
|
|
doctype.entities.each_value do |entity|
|
||
|
|
@@ -382,7 +382,9 @@ module REXML
|
||
|
|
else
|
||
|
|
# Replace all ampersands that aren't part of an entity
|
||
|
|
DocType::DEFAULT_ENTITIES.each_value do |entity|
|
||
|
|
- copy = copy.gsub(entity.value, "&#{entity.name};" )
|
||
|
|
+ if copy.include?(entity.value)
|
||
|
|
+ copy = copy.gsub(entity.value, "&#{entity.name};" )
|
||
|
|
+ end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
copy
|
||
|
|
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb
|
||
|
|
index d8b88e7..5eb1e5a 100644
|
||
|
|
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb
|
||
|
|
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb
|
||
|
|
@@ -590,6 +590,7 @@ module REXML
|
||
|
|
|
||
|
|
def evaluate_predicate(expression, nodesets)
|
||
|
|
enter(:predicate, expression, nodesets) if @debug
|
||
|
|
+ new_nodeset_count = 0
|
||
|
|
new_nodesets = nodesets.collect do |nodeset|
|
||
|
|
new_nodeset = []
|
||
|
|
subcontext = { :size => nodeset.size }
|
||
|
|
@@ -606,17 +607,20 @@ module REXML
|
||
|
|
result = result[0] if result.kind_of? Array and result.length == 1
|
||
|
|
if result.kind_of? Numeric
|
||
|
|
if result == node.position
|
||
|
|
- new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
|
||
|
|
+ new_nodeset_count += 1
|
||
|
|
+ new_nodeset << XPathNode.new(node, position: new_nodeset_count)
|
||
|
|
end
|
||
|
|
elsif result.instance_of? Array
|
||
|
|
if result.size > 0 and result.inject(false) {|k,s| s or k}
|
||
|
|
if result.size > 0
|
||
|
|
- new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
|
||
|
|
+ new_nodeset_count += 1
|
||
|
|
+ new_nodeset << XPathNode.new(node, position: new_nodeset_count)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
if result
|
||
|
|
- new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
|
||
|
|
+ new_nodeset_count += 1
|
||
|
|
+ new_nodeset << XPathNode.new(node, position: new_nodeset_count)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|