module Rsxml::Namespace
Public Instance Methods
compact all attribute QNames to Strings
# File lib/rsxml/namespace.rb, line 6 def compact_attr_qnames(ns_stack, attrs) Hash[attrs.map do |name,value| [compact_qname(ns_stack, name), value] end] end
produce a QName String from a [LocalPart, prefix, URI] triple
# File lib/rsxml/namespace.rb, line 26 def compact_qname(ns_stack, name) return name if name.is_a?(String) local_part, prefix, uri = name raise "invalid name: #{name}" if !prefix && uri if prefix if prefix!="xmlns" ns = find_namespace_uri(ns_stack, prefix, uri) raise "namespace prefix not bound to a namespace: '#{prefix}'" if ! ns end [prefix, local_part].map{|s| s.to_s unless s.to_s.empty?}.compact.join(':') else local_part end end
explode attribute QNames to [LocalPart, prefix, URI] triples,
# File lib/rsxml/namespace.rb, line 13 def explode_attr_qnames(ns_stack, attrs) Hash[attrs.map do |name, value| uq_name = explode_qname(ns_stack, name, true) local_part, prefix, uri = uq_name if !prefix || prefix=="" [local_part, value] else [uq_name, value] end end] end
split a QName into [LocalPart, prefix, URI] triple. fill out missing uris if necessary, and check QName is well specified
# File lib/rsxml/namespace.rb, line 44 def explode_qname(ns_stack, qname, attr=false) if qname.is_a?(Array) local_part, prefix, uri = qname if uri raise "invalid name: #{qname.inspect}" if !prefix bound_uri = find_namespace_uri(ns_stack, prefix) raise "namespace conflict: prefix '#{prefix}' refers to '#{uri}' and '#{bound_uri}'" if bound_uri && uri != bound_uri return [local_part, prefix, uri] elsif prefix uri = find_namespace_uri(ns_stack, prefix) raise "namespace prefix not bound: '#{prefix}'" if !uri return [local_part, prefix, uri] else return local_part end end local_part, prefix = split_qname(qname) if prefix if prefix=="xmlns" && attr [local_part, prefix] else uri = find_namespace_uri(ns_stack, prefix) raise "namespace prefix not bound: '#{prefix}'" if ! uri [local_part, prefix, uri] end else if attr local_part else default_uri = find_namespace_uri(ns_stack, "") if default_uri [local_part, "", default_uri] else local_part end end end end
produce a Hash of namespace declaration attributes with exploded QNames, from a Hash of namespace prefix bindings
# File lib/rsxml/namespace.rb, line 149 def exploded_namespace_declarations(ns) Hash[ns.map do |prefix, uri| if prefix=="" ["xmlns", uri] else [[prefix, "xmlns"], uri] end end] end
extract a Hash of {prefix=>uri} mappings from exploded QName element and attrs
# File lib/rsxml/namespace.rb, line 121 def extract_explicit_namespace_bindings(element_name, attrs) element_name_local_part, element_name_prefix, element_name_uri = element_name ns = {} ns[element_name_prefix] = element_name_uri if element_name_prefix && element_name_uri attrs.each do |name, value| attr_local_part, attr_prefix, attr_uri = name if attr_prefix && attr_uri raise "bindings clash: '#{attr_prefix}'=>'#{ns[attr_prefix]}' , '#{attr_prefix}'=>'#{attr_uri}'" if ns.has_key?(attr_prefix) && ns[attr_prefix]!=attr_uri ns[attr_prefix] = attr_uri end end ns end
returns the namespace uri for a prefix, if declared in the stack
# File lib/rsxml/namespace.rb, line 96 def find_namespace_uri(ns_stack, prefix, uri_check=nil) tns = ns_stack.reverse.find{|ns| ns.has_key?(prefix)} uri = tns[prefix] if tns raise "prefix: '#{prefix}' is bound to uri: '#{uri}', but should be '#{uri_check}'" if uri_check && uri && uri!=uri_check uri end
merges two sets of namespace bindings, raising error on clash
# File lib/rsxml/namespace.rb, line 172 def merge_namespace_bindings(ns1, ns2) m = ns1.clone ns2.each do |k,v| raise "bindings clash: '#{k}'=>'#{m[k]}' , '#{k}'=>'#{v}'" if m.has_key?(k) && m[k]!=v m[k]=v end m end
produces a Hash of compact namespace attributes from a Hash of namespace bindings
# File lib/rsxml/namespace.rb, line 161 def namespace_attributes(ns) Hash[ns.map do |prefix, uri| if prefix=="" ["xmlns", uri] else [["xmlns", prefix].join(":"), uri] end end] end
given the existing ns_stack
of ns bindings, a element_name
and it’s attributes
, return a pair [non_ns_attrs, ns_bindings]
containing non-ns related attributes, and namespace bindings for the current element, both those declared in attributes and declared implicitly through exploded element names
# File lib/rsxml/namespace.rb, line 185 def non_ns_attrs_ns_bindings(ns_stack, element_name, attrs) non_ns_attrs, ns_declared = partition_namespace_decls(attrs) ns_explicit = extract_explicit_namespace_bindings(element_name, attrs) ns_undeclared = undeclared_namespace_bindings(ns_stack + [ns_declared], ns_explicit) ns_bindings = merge_namespace_bindings(ns_declared, ns_undeclared) [non_ns_attrs, ns_bindings] end
split attributes into non-namespace related attrs and {prefix=>uri} namespace bindings
# File lib/rsxml/namespace.rb, line 104 def partition_namespace_decls(attrs) nonns_attrs = [] ns_bindings = [] attrs.each do |name, value| local_part, prefix = split_qname(name) if prefix && prefix=="xmlns" ns_bindings << [local_part, value] elsif !prefix && local_part=="xmlns" ns_bindings << ["", value] else nonns_attrs << [name, value] end end [Hash[nonns_attrs], Hash[ns_bindings]] end
split a qname String into a [local_part, prefix] pair
# File lib/rsxml/namespace.rb, line 85 def split_qname(qname) return qname if qname.is_a?(Array) if qname =~ /^[^:]+:[^:]+$/ [*qname.split(':')].reverse else qname end end
figure out which explicit namespaces need declaring
ns_stack
is the stack of namespace bindings ns_explicit
is the explicit refs for a element
# File lib/rsxml/namespace.rb, line 140 def undeclared_namespace_bindings(ns_stack, ns_explicit) Hash[ns_explicit.map do |prefix,uri| [prefix, uri] if !find_namespace_uri(ns_stack, prefix, uri) end.compact] end