14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""Registration facilities for DOM. This module should not be used
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodirectly. Instead, the functions getDOMImplementation and
34adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoregisterDOMImplementation should be imported from xml.dom."""
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom xml.dom.minicompat import *  # isinstance, StringTypes
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# This is a list of well-known implementations.  Well-known names
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# should be published by posting to xml-sig@python.org, and are
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# subsequently recorded in this file.
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaowell_known_implementations = {
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    'minidom':'xml.dom.minidom',
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    '4DOM': 'xml.dom.DOMImplementation',
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    }
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# DOM implementations not officially registered should register
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# themselves with their
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoregistered = {}
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef registerDOMImplementation(name, factory):
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """registerDOMImplementation(name, factory)
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Register the factory function with the name. The factory function
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    should return an object which implements the DOMImplementation
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    interface. The factory function can either return the same object,
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    or a new one (e.g. if that implementation supports some
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    customization)."""
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    registered[name] = factory
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _good_enough(dom, features):
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    "_good_enough(dom, features) -> Return 1 if the dom offers the features"
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for f,v in features:
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if not dom.hasFeature(f,v):
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return 0
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return 1
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef getDOMImplementation(name = None, features = ()):
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """getDOMImplementation(name = None, features = ()) -> DOM implementation.
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Return a suitable DOM implementation. The name is either
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    well-known, the module name of a DOM implementation, or None. If
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    it is not None, imports the corresponding module and returns
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    DOMImplementation object if the import succeeds.
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    If name is not given, consider the available implementations to
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    find one with the required feature set. If no implementation can
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    be found, raise an ImportError. The features list must be a sequence
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    of (feature, version) pairs which are passed to hasFeature."""
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    import os
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    creator = None
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    mod = well_known_implementations.get(name)
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if mod:
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        mod = __import__(mod, {}, {}, ['getDOMImplementation'])
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return mod.getDOMImplementation()
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif name:
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return registered[name]()
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif "PYTHON_DOM" in os.environ:
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return getDOMImplementation(name = os.environ["PYTHON_DOM"])
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # User did not specify a name, try implementations in arbitrary
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # order, returning the one that has the required features
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if isinstance(features, StringTypes):
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        features = _parse_feature_string(features)
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for creator in registered.values():
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dom = creator()
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if _good_enough(dom, features):
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return dom
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for creator in well_known_implementations.keys():
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            dom = getDOMImplementation(name = creator)
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except StandardError: # typically ImportError, or AttributeError
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            continue
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if _good_enough(dom, features):
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return dom
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    raise ImportError,"no suitable DOM implementation found"
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _parse_feature_string(s):
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    features = []
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    parts = s.split()
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    i = 0
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    length = len(parts)
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    while i < length:
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        feature = parts[i]
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if feature[0] in "0123456789":
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ValueError, "bad feature name: %r" % (feature,)
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        i = i + 1
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        version = None
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if i < length:
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            v = parts[i]
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if v[0] in "0123456789":
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                i = i + 1
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                version = v
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        features.append((feature, version))
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return tuple(features)
100