10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""Registration facilities for DOM. This module should not be used
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidirectly. Instead, the functions getDOMImplementation and
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiregisterDOMImplementation should be imported from xml.dom."""
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom xml.dom.minicompat import *  # isinstance, StringTypes
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# This is a list of well-known implementations.  Well-known names
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# should be published by posting to xml-sig@python.org, and are
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# subsequently recorded in this file.
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwell_known_implementations = {
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    'minidom':'xml.dom.minidom',
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    '4DOM': 'xml.dom.DOMImplementation',
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    }
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# DOM implementations not officially registered should register
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# themselves with their
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiregistered = {}
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef registerDOMImplementation(name, factory):
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """registerDOMImplementation(name, factory)
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Register the factory function with the name. The factory function
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    should return an object which implements the DOMImplementation
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    interface. The factory function can either return the same object,
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    or a new one (e.g. if that implementation supports some
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    customization)."""
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    registered[name] = factory
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _good_enough(dom, features):
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    "_good_enough(dom, features) -> Return 1 if the dom offers the features"
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for f,v in features:
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not dom.hasFeature(f,v):
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return 0
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return 1
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef getDOMImplementation(name = None, features = ()):
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """getDOMImplementation(name = None, features = ()) -> DOM implementation.
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Return a suitable DOM implementation. The name is either
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    well-known, the module name of a DOM implementation, or None. If
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    it is not None, imports the corresponding module and returns
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    DOMImplementation object if the import succeeds.
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    If name is not given, consider the available implementations to
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    find one with the required feature set. If no implementation can
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    be found, raise an ImportError. The features list must be a sequence
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    of (feature, version) pairs which are passed to hasFeature."""
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import os
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    creator = None
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod = well_known_implementations.get(name)
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if mod:
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        mod = __import__(mod, {}, {}, ['getDOMImplementation'])
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return mod.getDOMImplementation()
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    elif name:
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return registered[name]()
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    elif "PYTHON_DOM" in os.environ:
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return getDOMImplementation(name = os.environ["PYTHON_DOM"])
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # User did not specify a name, try implementations in arbitrary
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # order, returning the one that has the required features
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if isinstance(features, StringTypes):
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        features = _parse_feature_string(features)
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for creator in registered.values():
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dom = creator()
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if _good_enough(dom, features):
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return dom
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for creator in well_known_implementations.keys():
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dom = getDOMImplementation(name = creator)
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except StandardError: # typically ImportError, or AttributeError
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            continue
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if _good_enough(dom, features):
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return dom
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    raise ImportError,"no suitable DOM implementation found"
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _parse_feature_string(s):
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    features = []
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    parts = s.split()
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    i = 0
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    length = len(parts)
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    while i < length:
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        feature = parts[i]
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if feature[0] in "0123456789":
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise ValueError, "bad feature name: %r" % (feature,)
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = i + 1
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        version = None
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if i < length:
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            v = parts[i]
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if v[0] in "0123456789":
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                i = i + 1
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                version = v
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        features.append((feature, version))
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return tuple(features)
100