Skip to content

Commit cb15858

Browse files
committed
parser: keep the current namespaces instead of stack of Set
It improves namespace resolution performance for deep element.
1 parent 2b47b16 commit cb15858

File tree

1 file changed

+35
-10
lines changed

1 file changed

+35
-10
lines changed

lib/rexml/parsers/baseparser.rb

+35-10
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ def stream=( source )
181181
@tags = []
182182
@stack = []
183183
@entities = []
184-
@nsstack = []
184+
@namespaces = {}
185+
@namespaces_restore_stack = []
185186
end
186187

187188
def position
@@ -285,7 +286,6 @@ def pull_event
285286
@source.position = start_position
286287
raise REXML::ParseException.new(message, @source)
287288
end
288-
@nsstack.unshift(Set.new)
289289
name = parse_name(base_error_message)
290290
if @source.match(/\s*\[/um, true)
291291
id = [nil, nil, nil]
@@ -379,7 +379,7 @@ def pull_event
379379
val = attdef[4] if val == "#FIXED "
380380
pairs[attdef[0]] = val
381381
if attdef[0] =~ /^xmlns:(.*)/
382-
@nsstack[0] << $1
382+
@namespaces[$1] = val
383383
end
384384
end
385385
end
@@ -432,7 +432,7 @@ def pull_event
432432
# here explicitly.
433433
@source.ensure_buffer
434434
if @source.match("/", true)
435-
@nsstack.shift
435+
@namespaces_restore_stack.pop
436436
last_tag = @tags.pop
437437
md = @source.match(Private::CLOSE_PATTERN, true)
438438
if md and !last_tag
@@ -477,18 +477,18 @@ def pull_event
477477
@document_status = :in_element
478478
@prefixes.clear
479479
@prefixes << md[2] if md[2]
480-
@nsstack.unshift(curr_ns=Set.new)
481-
attributes, closed = parse_attributes(@prefixes, curr_ns)
480+
push_namespaces_restore
481+
attributes, closed = parse_attributes(@prefixes)
482482
# Verify that all of the prefixes have been defined
483483
for prefix in @prefixes
484-
unless @nsstack.find{|k| k.member?(prefix)}
484+
unless @namespaces.key?(prefix)
485485
raise UndefinedNamespaceException.new(prefix,@source,self)
486486
end
487487
end
488488

489489
if closed
490490
@closed = tag
491-
@nsstack.shift
491+
pop_namespaces_restore
492492
else
493493
if @tags.empty? and @have_root
494494
raise ParseException.new("Malformed XML: Extra tag at the end of the document (got '<#{tag}')", @source)
@@ -599,6 +599,31 @@ def unnormalize( string, entities=nil, filter=nil )
599599
end
600600

601601
private
602+
def add_namespace(prefix, uri)
603+
@namespaces_restore_stack.last[prefix] = @namespaces[prefix]
604+
if uri.nil?
605+
@namespaces.delete(prefix)
606+
else
607+
@namespaces[prefix] = uri
608+
end
609+
end
610+
611+
def push_namespaces_restore
612+
namespaces_restore = {}
613+
@namespaces_restore_stack.push(namespaces_restore)
614+
namespaces_restore
615+
end
616+
617+
def pop_namespaces_restore
618+
namespaces_restore = @namespaces_restore_stack.pop
619+
namespaces_restore.each do |prefix, uri|
620+
if uri.nil?
621+
@namespaces.delete(prefix)
622+
else
623+
@namespaces[prefix] = uri
624+
end
625+
end
626+
end
602627

603628
def record_entity_expansion(delta=1)
604629
@entity_expansion_count += delta
@@ -727,7 +752,7 @@ def process_instruction
727752
[:processing_instruction, name, content]
728753
end
729754

730-
def parse_attributes(prefixes, curr_ns)
755+
def parse_attributes(prefixes)
731756
attributes = {}
732757
closed = false
733758
while true
@@ -770,7 +795,7 @@ def parse_attributes(prefixes, curr_ns)
770795
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
771796
raise REXML::ParseException.new( msg, @source, self)
772797
end
773-
curr_ns << local_part
798+
add_namespace(local_part, value)
774799
elsif prefix
775800
prefixes << prefix unless prefix == "xml"
776801
end

0 commit comments

Comments
 (0)