Skip to content

Commit 8030c9e

Browse files
naitohtompng
andcommitted
Optimization of Element#namespace and Element#namespaces with @parent_namespaces cache
## Why? for fix get_namespace performance > # FIXME: This DOUBLES the time XPath searches take Co-authored-by: tomoya ishida <tomoyapenguin@gmail.com>
1 parent aa54918 commit 8030c9e

2 files changed

Lines changed: 12 additions & 18 deletions

File tree

lib/rexml/element.rb

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,8 @@ def prefixes
589589
# d.elements['//c'].namespaces # => {"x"=>"1", "y"=>"2", "z"=>"3"}
590590
#
591591
def namespaces
592-
namespaces = {}
593-
namespaces = parent.namespaces if parent
594-
namespaces = namespaces.merge( attributes.namespaces )
595-
return namespaces
592+
@parent_namespaces ||= parent ? parent.namespaces : {}
593+
@parent_namespaces.merge(attributes.namespaces)
596594
end
597595

598596
# :call-seq:
@@ -619,17 +617,9 @@ def namespace(prefix=nil)
619617
if prefix.nil?
620618
prefix = prefix()
621619
end
622-
if prefix == ''
623-
prefix = "xmlns"
624-
else
625-
prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
626-
end
627-
ns = nil
628-
target = self
629-
while ns.nil? and target
630-
ns = target.attributes[prefix]
631-
target = target.parent
632-
end
620+
prefix = (prefix == '') ? 'xmlns' : prefix.delete_prefix("xmlns:")
621+
ns = namespaces[prefix]
622+
633623
ns = '' if ns.nil? and prefix == 'xmlns'
634624
return ns
635625
end
@@ -653,6 +643,7 @@ def namespace(prefix=nil)
653643
# e.namespaces # => {"xmlns"=>"bar", "baz"=>"bat"}
654644
#
655645
def add_namespace( prefix, uri=nil )
646+
self.each{|e| e.reset_parent_namespaces }
656647
unless uri
657648
@attributes["xmlns"] = prefix
658649
else
@@ -685,6 +676,7 @@ def add_namespace( prefix, uri=nil )
685676
# d.to_s # => "<a/>"
686677
#
687678
def delete_namespace namespace="xmlns"
679+
self.each{|e| e.reset_parent_namespaces }
688680
namespace = "xmlns:#{namespace}" unless namespace == 'xmlns'
689681
attribute = attributes.get_attribute(namespace)
690682
attribute.remove unless attribute.nil?
@@ -1516,6 +1508,11 @@ def write(output=$stdout, indent=-1, transitive=false, ie_hack=false)
15161508
formatter.write( self, output )
15171509
end
15181510

1511+
protected
1512+
def reset_parent_namespaces
1513+
@parent_namespaces = nil
1514+
self.each{|e| e.reset_parent_namespaces }
1515+
end
15191516

15201517
private
15211518
def __to_xpath_helper node

lib/rexml/xpath_parser.rb

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,10 @@ def node_test(path_stack, nodesets, any_type: :element)
492492
if strict?
493493
raw_node.name == name and raw_node.namespace == ""
494494
else
495-
# FIXME: This DOUBLES the time XPath searches take
496495
ns = get_namespace(raw_node, prefix)
497496
raw_node.name == name and raw_node.namespace == ns
498497
end
499498
else
500-
# FIXME: This DOUBLES the time XPath searches take
501499
ns = get_namespace(raw_node, prefix)
502500
raw_node.name == name and raw_node.namespace == ns
503501
end
@@ -507,7 +505,6 @@ def node_test(path_stack, nodesets, any_type: :element)
507505
elsif prefix.empty?
508506
raw_node.name == name and raw_node.namespace == ""
509507
else
510-
# FIXME: This DOUBLES the time XPath searches take
511508
ns = get_namespace(raw_node.element, prefix)
512509
raw_node.name == name and raw_node.namespace == ns
513510
end

0 commit comments

Comments
 (0)