@@ -588,12 +588,7 @@ def prefixes
588588 # d.elements['//c'].namespaces # => {"x"=>"1", "y"=>"2", "z"=>"3"}
589589 #
590590 def namespaces
591- namespaces_cache = document &.__send__ ( :namespaces_cache )
592- if namespaces_cache
593- namespaces_cache [ self ] ||= calculate_namespaces
594- else
595- calculate_namespaces
596- end
591+ _calculate_namespaces
597592 end
598593
599594 # :call-seq:
@@ -618,13 +613,10 @@ def namespaces
618613 #
619614 def namespace ( prefix = nil )
620615 if prefix . nil?
621- prefix = prefix ( )
616+ _namespace_internal
617+ else
618+ _namespace_lookup_internal ( prefix )
622619 end
623- prefix = ( prefix == '' ) ? 'xmlns' : prefix . delete_prefix ( "xmlns:" )
624- ns = namespaces [ prefix ]
625-
626- ns = '' if ns . nil? and prefix == 'xmlns'
627- ns
628620 end
629621
630622 # :call-seq:
@@ -1507,15 +1499,32 @@ def write(output=$stdout, indent=-1, transitive=false, ie_hack=false)
15071499 formatter . write ( self , output )
15081500 end
15091501
1510- private
1511- def calculate_namespaces
1512- if parent
1513- parent . namespaces . merge ( attributes . namespaces )
1514- else
1515- attributes . namespaces
1516- end
1502+ # Returns namespace of the element
1503+ def _namespace_internal ( namespaces = _calculate_namespaces ) # :nodoc:
1504+ _namespace_lookup_internal ( prefix , namespaces )
1505+ end
1506+
1507+ # Lookup namespace for the given prefix in the context of the element
1508+ def _namespace_lookup_internal ( prefix , namespaces = _calculate_namespaces ) # :nodoc:
1509+ prefix = ( prefix == '' ) ? 'xmlns' : prefix . delete_prefix ( "xmlns:" )
1510+ ns = namespaces [ prefix ]
1511+ ns = '' if ns . nil? and prefix == 'xmlns'
1512+ ns
1513+ end
1514+
1515+ def _calculate_namespaces ( cache_hash = nil , attlist_mappings = nil ) # :nodoc:
1516+ return cache_hash [ self ] if cache_hash && cache_hash . key? ( self )
1517+
1518+ attlist_mappings ||= document &.doctype &._attlist_mappings || { }
1519+ inherited_namespaces = parent ? parent . _calculate_namespaces ( cache_hash , attlist_mappings ) : { }
1520+ attr_namespaces = attributes . _calculate_namespaces ( attlist_mappings )
1521+ namespaces = attr_namespaces . any? ? inherited_namespaces . merge ( attr_namespaces ) : inherited_namespaces
1522+ cache_hash [ self ] = namespaces if cache_hash
1523+ namespaces
15171524 end
15181525
1526+ private
1527+
15191528 def __to_xpath_helper node
15201529 rv = node . expanded_name . clone
15211530 if node . parent
@@ -2297,7 +2306,7 @@ def each
22972306 # attrs.get_attribute('nosuch') # => nil
22982307 #
22992308 def get_attribute ( name )
2300- fetch ( name , nil ) || attlist_attributes &.[] ( name )
2309+ fetch ( name , nil ) || attlist_attributes [ name ]
23012310 end
23022311
23032312 # :call-seq:
@@ -2368,11 +2377,7 @@ def prefixes
23682377 # d.root.attributes.namespaces # => {"xmlns"=>"foo", "x"=>"bar", "y"=>"twee"}
23692378 #
23702379 def namespaces
2371- namespaces = { }
2372- each_effective_attribute do |attribute |
2373- namespaces [ attribute . name ] = attribute . value if attribute . namespace_declaration?
2374- end
2375- namespaces
2380+ _calculate_namespaces
23762381 end
23772382
23782383 # :call-seq:
@@ -2503,33 +2508,40 @@ def get_attribute_ns(namespace, name)
25032508 end
25042509 end
25052510
2511+ def _calculate_namespaces ( attlist_mappings = nil ) # :nodoc:
2512+ namespaces = { }
2513+ each_effective_attribute ( attlist_mappings ) do |attribute |
2514+ namespaces [ attribute . name ] = attribute . value if attribute . namespace_declaration?
2515+ end
2516+ namespaces
2517+ end
2518+
25062519 private
25072520
25082521 # Iterates over the attributes of the element and those in the DTD.
25092522 # If the element has an attribute with the same name as one in the DTD,
25102523 # the element's attribute takes precedence.
2511- def each_effective_attribute
2512- return to_enum ( __method__ ) unless block_given?
2513- attr = attlist_attributes
2514- attr = attr ? attr . merge ( self ) : self
2515- attr . each_value do |attribute |
2524+ def each_effective_attribute ( attlist_mappings = nil )
2525+ return to_enum ( __method__ , attlist_mappings ) unless block_given?
2526+ attributes = attlist_attributes ( attlist_mappings ) . merge ( self )
2527+ attributes . each_value do |attribute |
25162528 yield attribute
25172529 end
25182530 end
25192531
25202532 alias each_own_attribute each_value
25212533 private :each_own_attribute
25222534
2523- def attlist_attributes
2524- doctype = @element . document &.doctype
2525- if doctype
2526- expn = @element . is_a? ( Document ) ? doctype . name : @element . expanded_name
2527- doctype . attribute_declarations_of ( expn ) . map do | key , value |
2528- attr = Attribute . new ( key , value )
2529- attr . element = @element
2530- [ key , attr ]
2531- end . to_h
2532- end
2535+ def attlist_attributes ( attlist_mappings = nil )
2536+ attlist_mappings || = @element . document &.doctype &. _attlist_mappings
2537+ return { } unless attlist_mappings
2538+
2539+ expn = @element . is_a? ( Document ) ? @element . doctype &. name : @element . expanded_name
2540+ attlist_mappings [ expn ] &. map do | key , value |
2541+ attr = Attribute . new ( key , value )
2542+ attr . element = @element
2543+ [ key , attr ]
2544+ end . to_h
25332545 end
25342546 end
25352547end
0 commit comments