Package pyxb :: Package namespace :: Module resolution |
[hide private]
[frames] | no frames]

# Source Code for Module pyxb.namespace.resolution

      1  # -*- coding: utf-8 -*-
      2  # Copyright 2009-2013, Peter A. Bigot
      3  #
      4  # Licensed under the Apache License, Version 2.0 (the "License"); you may
      5  # not use this file except in compliance with the License. You may obtain a
      6  # copy of the License at:
      7  #
      8  #            http://www.apache.org/licenses/LICENSE-2.0
      9  #
     10  # Unless required by applicable law or agreed to in writing, software
     11  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  # License for the specific language governing permissions and limitations
     14  # under the License.
     15
     16  """Classes and global objects related to resolving U{XML
     17  Namespaces<http://www.w3.org/TR/2006/REC-xml-names-20060816/index.html>}."""
     18
     19  import pyxb
     20  import pyxb.utils.utility
     21  from pyxb.namespace import archive, utility
     22  import logging
     23
     24  _log = logging.getLogger(__name__)
     25
     26 -class _Resolvable_mixin (pyxb.cscRoot):
     27      """Mix-in indicating that this object may have references to unseen named components.
     28
     29      This class is mixed-in to those XMLSchema components that have a reference
     30      to another component that is identified by a QName.  Resolution of that
     31      component may need to be delayed if the definition of the component has
     32      not yet been read.
     33      """
     34
     35      #_TraceResolution = True
     36      _TraceResolution = False
     37
     38 -    def isResolved (self):
     39          """Determine whether this named component is resolved.
     40
     41          Override this in the child class."""
     42          raise NotImplementedError("_Resolvable_mixin.isResolved in %s"% (type(self).__name__,))
     43
     44 -    def _resolve (self):
     45          """Perform whatever steps are required to resolve this component.
     46
     47          Resolution is performed in the context of the namespace to which the
     48          component belongs.  Invoking this method may fail to complete the
     49          resolution process if the component itself depends on unresolved
     50          components.  The sole caller of this should be
     51          L{_NamespaceResolution_mixin.resolveDefinitions}.
     52
     53          This method is permitted (nay, encouraged) to raise an exception if
     54          resolution requires interpreting a QName and the named component
     55          cannot be found.
     56
     57          Override this in the child class.  In the prefix, if L{isResolved} is
     58          true, return right away.  If something prevents you from completing
     59          resolution, invoke L{self._queueForResolution()} (so it is retried
     60          later) and immediately return self.  Prior to leaving after successful
     61          resolution discard any cached dom node by setting C{self.__domNode=None}.
     62
     63          @return: C{self}, whether or not resolution succeeds.
     64          @raise pyxb.SchemaValidationError: if resolution requlres a reference to an unknown component
     65          """
     66          raise NotImplementedError("_Resolvable_mixin._resolve in %s"% (type(self).__name__,))
     67
     68 -    def _queueForResolution (self, why=None, depends_on=None):
     69          """Short-hand to requeue an object if the class implements _namespaceContext().
     70          """
     71          if (why is not None) and self._TraceResolution:
     72              _log.info('Resolution delayed for %s: %s\n\tDepends on: %s', self, why, depends_on)
     73          self._namespaceContext().queueForResolution(self, depends_on)
     74
     75 -class _NamespaceResolution_mixin (pyxb.cscRoot):
     76      """Mix-in that aggregates those aspects of XMLNamespaces relevant to
     77      resolving component references.
     78      """
     79
     80      # A set of namespaces which some schema imported while processing with
     81      # this namespace as target.
     82      __importedNamespaces = None
     83
     84      # A set of namespaces which appear in namespace declarations of schema
     85      # with this namespace as target.
     86      __referencedNamespaces = None
     87
     88      # A list of Namespace._Resolvable_mixin instances that have yet to be
     89      # resolved.
     90      __unresolvedComponents = None
     91
     92      # A map from Namespace._Resolvable_mixin instances in
     93      # __unresolvedComponents to sets of other unresolved objects on which they
     94      # depend.
     95      __unresolvedDependents = None
     96
     97 -    def _reset (self):
     98          """CSC extension to reset fields of a Namespace.
     99
    100          This one handles component-resolution--related data."""
    101          getattr(super(_NamespaceResolution_mixin, self), '_reset', lambda *args, **kw: None)()
    102          self.__unresolvedComponents = []
    103          self.__unresolvedDependents = {}
    104          self.__importedNamespaces = set()
    105          self.__referencedNamespaces = set()
    106
    107 -    def _getState_csc (self, kw):
    108          kw.update({
    109                  'importedNamespaces': self.__importedNamespaces,
    110                  'referencedNamespaces': self.__referencedNamespaces,
    111                  })
    112          return getattr(super(_NamespaceResolution_mixin, self), '_getState_csc', lambda _kw: _kw)(kw)
    113
    114 -    def _setState_csc (self, kw):
    115          self.__importedNamespaces = kw['importedNamespaces']
    116          self.__referencedNamespaces = kw['referencedNamespaces']
    117          return getattr(super(_NamespaceResolution_mixin, self), '_setState_csc', lambda _kw: self)(kw)
    118
    119 -    def importNamespace (self, namespace):
    120          self.__importedNamespaces.add(namespace)
    121          return self
    122
    123 -    def _referenceNamespace (self, namespace):
    124          self._activate()
    125          self.__referencedNamespaces.add(namespace)
    126          return self
    127
    128 -    def importedNamespaces (self):
    129          """Return the set of namespaces which some schema imported while
    130          processing with this namespace as target."""
    131          return frozenset(self.__importedNamespaces)
    132
    133 -    def _transferReferencedNamespaces (self, module_record):
    134          assert isinstance(module_record, archive.ModuleRecord)
    135          module_record._setReferencedNamespaces(self.__referencedNamespaces)
    136          self.__referencedNamespaces.clear()
    137
    138 -    def referencedNamespaces (self):
    139          """Return the set of namespaces which appear in namespace declarations
    140          of schema with this namespace as target."""
    141          return frozenset(self.__referencedNamespaces)
    142
    143 -    def queueForResolution (self, resolvable, depends_on=None):
    144          """Invoked to note that a component may have references that will need
    145          to be resolved.
    146
    147          Newly created named components are often unresolved, as are components
    148          which, in the course of resolution, are found to depend on another
    149          unresolved component.
    150
    151          @param resolvable: An instance of L{_Resolvable_mixin} that is later to
    152          be resolved.
    153
    154          @keyword depends_on: C{None}, or an instance of L{_Resolvable_mixin}
    155          which C{resolvable} requires to be resolved in order to resolve
    156          itself.
    157
    158          @return: C{resolvable}
    159          """
    160          assert isinstance(resolvable, _Resolvable_mixin)
    161          if not resolvable.isResolved():
    162              assert depends_on is None or isinstance(depends_on, _Resolvable_mixin)
    163              self.__unresolvedComponents.append(resolvable)
    164              if depends_on is not None and not depends_on.isResolved():
    165                  from pyxb.xmlschema import structures
    166                  assert isinstance(depends_on, _Resolvable_mixin)
    167                  assert isinstance(depends_on, structures._NamedComponent_mixin)
    168                  self.__unresolvedDependents.setdefault(resolvable, set()).add(depends_on)
    169          return resolvable
    170
    171 -    def needsResolution (self):
    172          """Return C{True} iff this namespace has not been resolved."""
    173          return self.__unresolvedComponents is not None
    174
    175 -    def _replaceComponent_csc (self, existing_def, replacement_def):
    176          """Replace a component definition if present in the list of unresolved components.
    177          """
    178          try:
    179              index = self.__unresolvedComponents.index(existing_def)
    180              if (replacement_def is None) or (replacement_def in self.__unresolvedComponents):
    181                  del self.__unresolvedComponents[index]
    182              else:
    183                  assert isinstance(replacement_def, _Resolvable_mixin)
    184                  self.__unresolvedComponents[index] = replacement_def
    185              # Rather than assume the replacement depends on the same
    186              # resolvables as the original, just wipe the dependency record:
    187              # it'll get recomputed later if it's still important.
    188              if existing_def in self.__unresolvedDependents:
    189                  del self.__unresolvedDependents[existing_def]
    190          except ValueError:
    191              pass
    192          return getattr(super(_NamespaceResolution_mixin, self), '_replaceComponent_csc', lambda *args, **kw: replacement_def)(existing_def, replacement_def)
    193
    194 -    def resolveDefinitions (self, allow_unresolved=False):
    195          """Loop until all references within the associated resolvable objects
    196          have been resolved.
    197
    198          This method iterates through all components on the unresolved list,
    199          invoking the _resolve method of each.  If the component could not be
    200          resolved in this pass, it iis placed back on the list for the next
    201          iteration.  If an iteration completes without resolving any of the
    202          unresolved components, a pyxb.NotInNamespaceError exception is raised.
    203
    204          @note: Do not invoke this until all top-level definitions for the
    205          namespace have been provided.  The resolution routines are entitled to
    206          raise a validation exception if a reference to an unrecognized
    207          component is encountered.
    208          """
    209          if not self.needsResolution():
    210              return True
    211
    212          while 0 < len(self.__unresolvedComponents):
    213              # Save the list of unresolved objects, reset the list to capture
    214              # any new objects defined during resolution, and attempt the
    215              # resolution for everything that isn't resolved.
    216              unresolved = self.__unresolvedComponents
    217
    218              self.__unresolvedComponents = []
    219              self.__unresolvedDependents = {}
    220              for resolvable in unresolved:
    221                  # Attempt the resolution.
    222                  resolvable._resolve()
    223
    224                  # Either we resolved it, or we queued it to try again later
    225                  assert resolvable.isResolved() or (resolvable in self.__unresolvedComponents), 'Lost resolvable %s' % (resolvable,)
    226
    227                  # We only clone things that have scope None.  We never
    228                  # resolve things that have scope None.  Therefore, we
    229                  # should never have resolved something that has
    230                  # clones.
    231                  if (resolvable.isResolved() and (resolvable._clones() is not None)):
    232                      assert False
    233              if self.__unresolvedComponents == unresolved:
    234                  if allow_unresolved:
    235                      return False
    236                  # This only happens if we didn't code things right, or the
    237                  # there is a circular dependency in some named component
    238                  # (i.e., the schema designer didn't do things right).
    239                  failed_components = []
    240                  from pyxb.xmlschema import structures
    241                  for d in self.__unresolvedComponents:
    242                      if isinstance(d, structures._NamedComponent_mixin):
    243                          failed_components.append('%s named %s' % (d.__class__.__name__, d.name()))
    244                      else:
    245                          failed_components.append('Anonymous %s' % (d.__class__.__name__,))
    246                  raise pyxb.NotInNamespaceError('Infinite loop in resolution:\n  %s' % ("\n  ".join(failed_components),))
    247
    248          # Replace the list of unresolved components with None, so that
    249          # attempts to subsequently add another component fail.
    250          self.__unresolvedComponents = None
    251          self.__unresolvedDependents = None
    252
    253          # NOTE: Dependencies may require that we keep these around for a while
    254          # longer.
    255          #
    256          # Remove the namespace context from everything, since we won't be
    257          # resolving anything else.
    258          self._releaseNamespaceContexts()
    259
    260          return True
    261
    262 -    def _unresolvedComponents (self):
    263          """Returns a reference to the list of unresolved components."""
    264          return self.__unresolvedComponents
    265
    266 -    def _unresolvedDependents (self):
    267          """Returns a map from unresolved components to sets of components that
    268          must be resolved first."""
    269          return self.__unresolvedDependents
    270
    271 -def ResolveSiblingNamespaces (sibling_namespaces):
    272      """Resolve all components in the sibling_namespaces.
    273
    274      @param sibling_namespaces : A set of namespaces expected to be closed
    275      under dependency."""
    276
    277      for ns in sibling_namespaces:
    278          ns.configureCategories([archive.NamespaceArchive._AnonymousCategory()])
    279          ns.validateComponentModel()
    280
    281      def __keyForCompare (dependency_map):
    282          """Sort namespaces so dependencies get resolved first.
    283
    284          Uses the trick underlying functools.cmp_to_key(), but optimized for
    285          this special case.  The dependency map is incorporated into the class
    286          definition by scope.
    287          """
    288          class K (object):
    289              def __init__ (self, ns, *args):
    290                  self.__ns = ns
    291
    292              # self compares less than other if self.ns is in the dependency set
    293              # of other.ns but not vice-versa.
    294              def __lt__ (self, other):
    295                  return ((self.__ns in dependency_map.get(other.__ns, set())) \
    296                              and not (other.__ns in dependency_map.get(self.__ns, set())))
    297
    298              # self compares equal to other if their namespaces are either
    299              # mutually dependent or independent.
    300              def __eq__ (self, other):
    301                  return (self.__ns in dependency_map.get(other.__ns, set())) == (other.__ns in dependency_map.get(self.__ns, set()))
    302
    303              # All other order metrics are derived.
    304              def __ne__ (self, other):
    305                  return not self.__eq__(other)
    306              def __le__ (self, other):
    307                  return self.__lt__(other) or self.__eq__(other)
    308              def __gt__ (self, other):
    309                  return other.__lt__(self.__ns)
    310              def __ge__ (self, other):
    311                  return other.__lt__(self.__ns) or self.__eq__(other)
    312          return K
    313
    314      need_resolved_set = set(sibling_namespaces)
    315      dependency_map = {}
    316      last_state = None
    317      while need_resolved_set:
    318          need_resolved_list = list(need_resolved_set)
    319          if dependency_map:
    320              need_resolved_list.sort(key=__keyForCompare(dependency_map))
    321          need_resolved_set = set()
    322          dependency_map = {}
    323          for ns in need_resolved_list:
    324              if not ns.needsResolution():
    325                  continue
    326              if not ns.resolveDefinitions(allow_unresolved=True):
    327                  deps = dependency_map.setdefault(ns, set())
    328                  for (c, dcs) in ns._unresolvedDependents().iteritems():
    329                      for dc in dcs:
    330                          dns = dc.expandedName().namespace()
    331                          if dns != ns:
    332                              deps.add(dns)
    333                  _log.info('Holding incomplete resolution %s depending on: ', ns.uri(), u' ; '.join([ unicode(_dns) for _dns in deps ]))
    334                  need_resolved_set.add(ns)
    335          # Exception termination check: if we have the same set of incompletely
    336          # resolved namespaces, and each has the same number of unresolved
    337          # components, assume there's an truly unresolvable dependency: either
    338          # due to circularity, or because there was an external namespace that
    339          # was missed from the sibling list.
    340          state = []
    341          for ns in need_resolved_set:
    342              state.append( (ns, len(ns._unresolvedComponents())) )
    343          state = tuple(state)
    344          if last_state == state:
    345              raise pyxb.LogicError('Unexpected external dependency in sibling namespaces: %s' % (u"\n  ".join( [unicode(_ns) for _ns in need_resolved_set ]),))
    346          last_state = state
    347
    348 -class NamespaceContext (object):
    349      """Records information associated with namespaces at a DOM node.
    350      """
    351
    352 -    def __str__ (self):
    353          rv = [ u'NamespaceContext ' ]
    354          if self.defaultNamespace() is not None:
    355              rv.extend([ '(defaultNamespace=', unicode(self.defaultNamespace()), ') '])
    356          if self.targetNamespace() is not None:
    357              rv.extend([ '(targetNamespace=', unicode(self.targetNamespace()), ') '])
    358          rv.append("\n")
    359          for (pfx, ns) in self.inScopeNamespaces().iteritems():
    360              if pfx is not None:
    361                  rv.append('  xmlns:%s=%s' % (pfx, unicode(ns)))
    362          return u''.join(rv)
    363
    364      __TargetNamespaceAttributes = { }
    365      @classmethod
    366 -    def _AddTargetNamespaceAttribute (cls, expanded_name, attribute_name):
    367          assert expanded_name is not None
    368          cls.__TargetNamespaceAttributes[expanded_name] = attribute_name
    369      @classmethod
    370 -    def _TargetNamespaceAttribute (cls, expanded_name):
    371          return cls.__TargetNamespaceAttributes.get(expanded_name)
    372
    373      # Support for holding onto referenced namespaces until we have a target
    374      # namespace to give them to.
    375      __pendingReferencedNamespaces = None
    376
    377 -    def defaultNamespace (self):
    378          """The default namespace in effect at this node.  E.g., C{xmlns="URN:default"}."""
    379          return self.__defaultNamespace
    380      __defaultNamespace = None
    381
    382      # If C{True}, this context is within a schema that has no target
    383      # namespace, and we should use the target namespace as a fallback if no
    384      # default namespace is available and no namespace prefix appears on a
    385      # QName.  This situation arises when a top-level schema has an absent
    386      # target namespace, or when a schema with an absent target namespace is
    387      # being included into a schema with a non-absent target namespace.
    388      __fallbackToTargetNamespace = False
    389
    390 -    def targetNamespace (self):
    391          """The target namespace in effect at this node.  Usually from the
    392          C{targetNamespace} attribute.  If no namespace is specified for the
    393          schema, an absent namespace was assigned upon creation and will be
    394          returned."""
    395          return self.__targetNamespace
    396      __targetNamespace = None
    397
    398 -    def inScopeNamespaces (self):
    399          """Map from prefix strings to L{Namespace} instances associated with those
    400          prefixes.  The prefix C{None} identifies the default namespace."""
    401          return self.__inScopeNamespaces
    402      __inScopeNamespaces = None
    403
    404 -    def prefixForNamespace (self, namespace):
    405          """Return a prefix associated with the given namespace in this
    406          context, or None if the namespace is the default or is not in
    407          scope."""
    408          for (pfx, ns) in self.__inScopeNamespaces.iteritems():
    409              if namespace == ns:
    410                  return pfx
    411          return None
    412
    413      @classmethod
    414 -    def GetNodeContext (cls, node, **kw):
    415          """Get the L{NamespaceContext} instance that was assigned to the node.
    416
    417          If none has been assigned and keyword parameters are present, create
    418          one treating this as the root node and the keyword parameters as
    419          configuration information (e.g., default_namespace).
    420
    421          @raise pyxb.LogicError: no context is available and the keywords
    422          required to create one were not provided
    423          """
    424          try:
    425              return node.__namespaceContext
    426          except AttributeError:
    427              return NamespaceContext(node, **kw)
    428
    429 -    def setNodeContext (self, node):
    430          node.__namespaceContext = self
    431
    432 -    def processXMLNS (self, prefix, uri):
    433          if not self.__mutableInScopeNamespaces:
    434              self.__inScopeNamespaces = self.__inScopeNamespaces.copy()
    435              self.__mutableInScopeNamespaces = True
    436          if uri:
    437              if prefix is None:
    438                  ns = self.__defaultNamespace = utility.NamespaceForURI(uri, create_if_missing=True)
    439                  self.__inScopeNamespaces[None] = self.__defaultNamespace
    440              else:
    441                  ns = utility.NamespaceForURI(uri, create_if_missing=True)
    442                  self.__inScopeNamespaces[prefix] = ns
    443                  #if ns.prefix() is None:
    444                  #    ns.setPrefix(prefix)
    445                  # @todo should we record prefix in namespace so we can use it
    446                  # during generation?  I'd rather make the user specify what to
    447                  # use.
    448              if self.__targetNamespace:
    449                  self.__targetNamespace._referenceNamespace(ns)
    450              else:
    451                  self.__pendingReferencedNamespaces.add(ns)
    452          else:
    453              # NB: XMLNS 6.2 says that you can undefine a default
    454              # namespace, but does not say anything explicitly about
    455              # undefining a prefixed namespace.  XML-Infoset 2.2
    456              # paragraph 6 implies you can do this, but expat blows up
    457              # if you try it.  I don't think it's legal.
    458              if prefix is not None:
    459                  raise pyxb.NamespaceError(self, 'Attempt to undefine non-default namespace %s' % (prefix,))
    460              self.__inScopeNamespaces.pop(prefix, None)
    461              self.__defaultNamespace = None
    462
    463 -    def finalizeTargetNamespace (self, tns_uri=None, including_context=None):
    464          if tns_uri is not None:
    465              assert 0 < len(tns_uri)
    466              # Do not prevent overwriting target namespace; need this for WSDL
    467              # files where an embedded schema inadvertently inherits a target
    468              # namespace from its enclosing definitions element.  Note that if
    469              # we don't check this here, we do have to check it when schema
    470              # documents are included into parent schema documents.
    471              self.__targetNamespace = utility.NamespaceForURI(tns_uri, create_if_missing=True)
    472          elif self.__targetNamespace is None:
    473              if including_context is not None:
    474                  self.__targetNamespace = including_context.targetNamespace()
    475                  self.__fallbackToTargetNamespace = True
    476              elif tns_uri is None:
    477                  self.__targetNamespace = utility.CreateAbsentNamespace()
    478              else:
    479                  self.__targetNamespace = utility.NamespaceForURI(tns_uri, create_if_missing=True)
    480          if self.__pendingReferencedNamespaces is not None:
    481              [ self.__targetNamespace._referenceNamespace(_ns) for _ns in self.__pendingReferencedNamespaces ]
    482              self.__pendingReferencedNamespace = None
    483          assert self.__targetNamespace is not None
    484          if (not self.__fallbackToTargetNamespace) and self.__targetNamespace.isAbsentNamespace():
    485              self.__fallbackToTargetNamespace = True
    486
    487 -    def __init__ (self,
    488                    dom_node=None,
    489                    parent_context=None,
    490                    including_context=None,
    491                    recurse=True,
    492                    default_namespace=None,
    493                    target_namespace=None,
    494                    in_scope_namespaces=None,
    495                    expanded_name=None,
    496                    finalize_target_namespace=True):  # MUST BE True for WSDL to work with minidom
    497          """Determine the namespace context that should be associated with the
    498          given node and, optionally, its element children.
    499
    500          @param dom_node: The DOM node
    501          @type dom_node: C{xml.dom.Element}
    502          @keyword parent_context: Optional value that specifies the context
    503          associated with C{dom_node}'s parent node.  If not provided, only the
    504          C{xml} namespace is in scope.
    505          @type parent_context: L{NamespaceContext}
    506          @keyword recurse: If True (default), create namespace contexts for all
    507          element children of C{dom_node}
    508          @type recurse: C{bool}
    509          @keyword default_namespace: Optional value to set as the default
    510          namespace.  Values from C{parent_context} would override this, as
    511          would an C{xmlns} attribute in the C{dom_node}.
    512          @type default_namespace: L{NamespaceContext}
    513          @keyword target_namespace: Optional value to set as the target
    514          namespace.  Values from C{parent_context} would override this, as
    515          would a C{targetNamespace} attribute in the C{dom_node}
    516          @type target_namespace: L{NamespaceContext}
    517          @keyword in_scope_namespaces: Optional value to set as the initial set
    518          of in-scope namespaces.  The always-present namespaces are added to
    519          this if necessary.
    520          @type in_scope_namespaces: C{dict} mapping C{string} to L{Namespace}.
    521          """
    522          from pyxb.namespace import builtin
    523
    524          if dom_node is not None:
    525              try:
    526                  assert dom_node.__namespaceContext is None
    527              except AttributeError:
    528                  pass
    529              dom_node.__namespaceContext = self
    530
    531          self.__defaultNamespace = default_namespace
    532          self.__targetNamespace = target_namespace
    533          self.__inScopeNamespaces = builtin._UndeclaredNamespaceMap
    534          self.__mutableInScopeNamespaces = False
    535
    536          if in_scope_namespaces is not None:
    537              if parent_context is not None:
    538                  raise pyxb.LogicError('Cannot provide both parent_context and in_scope_namespaces')
    539              self.__inScopeNamespaces = builtin._UndeclaredNamespaceMap.copy()
    540              self.__inScopeNamespaces.update(in_scope_namespaces)
    541              self.__mutableInScopeNamespaces = True
    542
    543          if parent_context is not None:
    544              self.__inScopeNamespaces = parent_context.inScopeNamespaces()
    545              self.__mutableInScopeNamespaces = False
    546              self.__defaultNamespace = parent_context.defaultNamespace()
    547              self.__targetNamespace = parent_context.targetNamespace()
    548              self.__fallbackToTargetNamespace = parent_context.__fallbackToTargetNamespace
    549
    550          if self.__targetNamespace is None:
    551              self.__pendingReferencedNamespaces = set()
    552          attribute_map = {}
    553          if dom_node is not None:
    554              if expanded_name is None:
    555                  expanded_name = pyxb.namespace.ExpandedName(dom_node)
    556              for ai in range(dom_node.attributes.length):
    557                  attr = dom_node.attributes.item(ai)
    558                  if builtin.XMLNamespaces.uri() == attr.namespaceURI:
    559                      prefix = attr.localName
    560                      if 'xmlns' == prefix:
    561                          prefix = None
    562                      self.processXMLNS(prefix, attr.value)
    563                  else:
    564                      if attr.namespaceURI is not None:
    565                          uri = utility.NamespaceForURI(attr.namespaceURI, create_if_missing=True)
    566                          key = pyxb.namespace.ExpandedName(uri, attr.localName)
    567                      else:
    568                          key = pyxb.namespace.ExpandedName(None, attr.localName)
    569                      attribute_map[key] = attr.value
    570
    571          if finalize_target_namespace:
    572              tns_uri = None
    573              tns_attr = self._TargetNamespaceAttribute(expanded_name)
    574              if tns_attr is not None:
    575                  tns_uri = attribute_map.get(tns_attr)
    576                  self.finalizeTargetNamespace(tns_uri, including_context=including_context)
    577
    578          # Store in each node the in-scope namespaces at that node;
    579          # we'll need them for QName interpretation of attribute
    580          # values.
    581          if (dom_node is not None) and recurse:
    582              from xml.dom import Node
    583              assert Node.ELEMENT_NODE == dom_node.nodeType
    584              for cn in dom_node.childNodes:
    585                  if Node.ELEMENT_NODE == cn.nodeType:
    586                      NamespaceContext(cn, self, True)
    587
    588 -    def interpretQName (self, name, namespace=None):
    589          """Convert the provided name into an L{ExpandedName}, i.e. a tuple of
    590          L{Namespace} and local name.
    591
    592          If the name includes a prefix, that prefix must map to an in-scope
    593          namespace in this context.  Absence of a prefix maps to
    594          L{defaultNamespace()}, which must be provided (or defaults to the
    595          target namespace, if that is absent).
    596
    597          @param name: A QName.
    598          @type name: C{str} or C{unicode}
    599          @param name: Optional namespace to use for unqualified names when
    600          there is no default namespace.  Note that a defined default namespace,
    601          even if absent, supersedes this value.
    602          @return: An L{ExpandedName} tuple: ( L{Namespace}, C{str} )
    603          @raise pyxb.SchemaValidationError: The prefix is not in scope
    604          @raise pyxb.SchemaValidationError: No prefix is given and the default namespace is absent
    605          """
    606          assert isinstance(name, (str, unicode))
    607          if 0 <= name.find(':'):
    608              (prefix, local_name) = name.split(':', 1)
    609              assert self.inScopeNamespaces() is not None
    610              namespace = self.inScopeNamespaces().get(prefix)
    611              if namespace is None:
    612                  raise pyxb.SchemaValidationError('No namespace declared for QName %s prefix' % (name,))
    613          else:
    614              local_name = name
    615              # Context default supersedes caller-provided namespace
    616              if self.defaultNamespace() is not None:
    617                  namespace = self.defaultNamespace()
    618              # If there's no default namespace, but there is a fallback
    619              # namespace, use that instead.
    620              if (namespace is None) and self.__fallbackToTargetNamespace:
    621                  namespace = self.targetNamespace()
    622              if namespace is None:
    623                  raise pyxb.SchemaValidationError('QName %s with absent default namespace cannot be resolved' % (local_name,))
    624          # Anything we're going to look stuff up in requires a component model.
    625          # Make sure we can load one, unless we're looking up in the thing
    626          # we're constructing (in which case it's being built right now).
    627          if (namespace != self.targetNamespace()):
    628              namespace.validateComponentModel()
    629          return pyxb.namespace.ExpandedName(namespace, local_name)
    630
    631 -    def queueForResolution (self, component, depends_on=None):
    632          """Forwards to L{queueForResolution()<Namespace.queueForResolution>} in L{targetNamespace()}."""
    633          assert isinstance(component, _Resolvable_mixin)
    634          return self.targetNamespace().queueForResolution(component, depends_on)
    635
    636  ## Local Variables:
    637  ## fill-column:78
    638  ## End:
    639