1 # module-level API for namespace implementations
3 class LxmlRegistryError(LxmlError):
4 u"""Base class of lxml registry errors.
8 class NamespaceRegistryError(LxmlRegistryError):
9 u"""Error registering a namespace extension.
14 cdef class _NamespaceRegistry:
15 u"Dictionary-like namespace registry"
17 cdef object _ns_uri_utf
19 cdef char* _c_ns_uri_utf
20 def __init__(self, ns_uri):
23 self._ns_uri_utf = None
24 self._c_ns_uri_utf = NULL
26 self._ns_uri_utf = _utf8(ns_uri)
27 self._c_ns_uri_utf = _cstr(self._ns_uri_utf)
30 def update(self, class_dict_iterable):
31 u"""update(self, class_dict_iterable)
33 Forgivingly update the registry.
35 If registered values do not match the required type for this
36 registry, or if their name starts with '_', they will be
37 silently discarded. This allows registrations at the module or
38 class level using vars(), globals() etc."""
39 if hasattr(class_dict_iterable, u'items'):
40 class_dict_iterable = class_dict_iterable.items()
41 for name, item in class_dict_iterable:
42 if (name is None or name[:1] != u'_') and callable(item):
45 def __getitem__(self, name):
48 return self._get(name)
50 def __delitem__(self, name):
53 del self._entries[name]
55 cdef object _get(self, object name):
56 cdef python.PyObject* dict_result
57 dict_result = python.PyDict_GetItem(self._entries, name)
58 if dict_result is NULL:
59 raise KeyError, u"Name not registered."
60 return <object>dict_result
62 cdef object _getForString(self, char* name):
63 cdef python.PyObject* dict_result
64 dict_result = python.PyDict_GetItem(self._entries, name)
65 if dict_result is NULL:
66 raise KeyError, u"Name not registered."
67 return <object>dict_result
70 return iter(self._entries)
73 return list(self._entries.items())
76 return iter(self._entries.items())
79 python.PyDict_Clear(self._entries)
81 cdef class _ClassNamespaceRegistry(_NamespaceRegistry):
82 u"Dictionary-like registry for namespace implementation classes"
83 def __setitem__(self, name, item):
84 if not python.PyType_Check(item) or not issubclass(item, ElementBase):
85 raise NamespaceRegistryError, \
86 u"Registered element classes must be subtypes of ElementBase"
89 self._entries[name] = item
92 return u"Namespace(%r)" % self._ns_uri
95 cdef class ElementNamespaceClassLookup(FallbackElementClassLookup):
96 u"""ElementNamespaceClassLookup(self, fallback=None)
98 Element class lookup scheme that searches the Element class in the
101 cdef object _namespace_registries
102 def __init__(self, ElementClassLookup fallback=None):
103 self._namespace_registries = {}
104 FallbackElementClassLookup.__init__(self, fallback)
105 self._lookup_function = _find_nselement_class
107 def get_namespace(self, ns_uri):
108 u"""get_namespace(self, ns_uri)
110 Retrieve the namespace object associated with the given URI.
112 Creates a new one if it does not yet exist."""
114 ns_utf = _utf8(ns_uri)
118 return self._namespace_registries[ns_utf]
120 registry = self._namespace_registries[ns_utf] = \
121 _ClassNamespaceRegistry(ns_uri)
124 cdef object _find_nselement_class(state, _Document doc, xmlNode* c_node):
125 cdef python.PyObject* dict_result
126 cdef ElementNamespaceClassLookup lookup
127 cdef _NamespaceRegistry registry
128 cdef char* c_namespace_utf
130 return _lookupDefaultElementClass(None, doc, c_node)
132 lookup = <ElementNamespaceClassLookup>state
133 if c_node.type != tree.XML_ELEMENT_NODE:
134 return _callLookupFallback(lookup, doc, c_node)
136 c_namespace_utf = _getNs(c_node)
137 if c_namespace_utf is not NULL:
138 dict_result = python.PyDict_GetItem(
139 lookup._namespace_registries, c_namespace_utf)
141 dict_result = python.PyDict_GetItem(
142 lookup._namespace_registries, None)
143 if dict_result is not NULL:
144 registry = <_NamespaceRegistry>dict_result
145 classes = registry._entries
147 if c_node.name is not NULL:
148 dict_result = python.PyDict_GetItem(
149 classes, c_node.name)
153 if dict_result is NULL:
154 dict_result = python.PyDict_GetItem(classes, None)
156 if dict_result is not NULL:
157 return <object>dict_result
158 return _callLookupFallback(lookup, doc, c_node)
161 ################################################################################
162 # XPath extension functions
164 cdef dict __FUNCTION_NAMESPACE_REGISTRIES
165 __FUNCTION_NAMESPACE_REGISTRIES = {}
167 def FunctionNamespace(ns_uri):
168 u"""FunctionNamespace(ns_uri)
170 Retrieve the function namespace object associated with the given
173 Creates a new one if it does not yet exist. A function namespace
174 can only be used to register extension functions."""
176 ns_utf = _utf8(ns_uri)
180 return __FUNCTION_NAMESPACE_REGISTRIES[ns_utf]
182 registry = __FUNCTION_NAMESPACE_REGISTRIES[ns_utf] = \
183 _XPathFunctionNamespaceRegistry(ns_uri)
186 cdef class _FunctionNamespaceRegistry(_NamespaceRegistry):
187 def __setitem__(self, name, item):
188 if not callable(item):
189 raise NamespaceRegistryError, \
190 u"Registered functions must be callable."
193 u"extensions must have non empty names"
194 self._entries[_utf8(name)] = item
197 return u"FunctionNamespace(%r)" % self._ns_uri
199 cdef class _XPathFunctionNamespaceRegistry(_FunctionNamespaceRegistry):
201 cdef object _prefix_utf
204 u"Namespace prefix for extension functions."
206 self._prefix = None # no prefix configured
207 self._prefix_utf = None
209 if self._prefix is None:
213 def __set__(self, prefix):
215 prefix = None # empty prefix
217 self._prefix_utf = None
219 self._prefix_utf = _utf8(prefix)
220 self._prefix = prefix
222 cdef list _find_all_extension_prefixes():
223 u"Internal lookup function to find all function prefixes for XSLT/XPath."
224 cdef _XPathFunctionNamespaceRegistry registry
225 cdef list ns_prefixes = []
226 for registry in __FUNCTION_NAMESPACE_REGISTRIES.itervalues():
227 if registry._prefix_utf is not None:
228 if registry._ns_uri_utf is not None:
230 (registry._prefix_utf, registry._ns_uri_utf))
233 cdef object _find_extension(ns_uri_utf, name_utf):
234 cdef python.PyObject* dict_result
235 dict_result = python.PyDict_GetItem(
236 __FUNCTION_NAMESPACE_REGISTRIES, ns_uri_utf)
237 if dict_result is NULL:
239 extensions = (<_NamespaceRegistry>dict_result)._entries
240 dict_result = python.PyDict_GetItem(extensions, name_utf)
241 if dict_result is NULL:
244 return <object>dict_result