module Rsxml::Namespace

Public Instance Methods

compact_attr_qnames(ns_stack, attrs) click to toggle source

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
compact_qname(ns_stack, name) click to toggle source

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_attr_qnames(ns_stack, attrs) click to toggle source

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
explode_qname(ns_stack, qname, attr=false) click to toggle source

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
exploded_namespace_declarations(ns) click to toggle source

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_explicit_namespace_bindings(element_name, attrs) click to toggle source

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
find_namespace_uri(ns_stack, prefix, uri_check=nil) click to toggle source

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
merge_namespace_bindings(ns1, ns2) click to toggle source

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
namespace_attributes(ns) click to toggle source

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
non_ns_attrs_ns_bindings(ns_stack, element_name, attrs) click to toggle source

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
partition_namespace_decls(attrs) click to toggle source

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_qname(qname) click to toggle source

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
undeclared_namespace_bindings(ns_stack, ns_explicit) click to toggle source

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