Skip to content

Commit

Permalink
[svn r3363] r3641@delle: sbehnel | 2008-02-27 10:52:36 +0100
Browse files Browse the repository at this point in the history
 moved read-only tree implementation from lxml.pyclasslookup into lxml.etree

--HG--
branch : trunk
rename : src/lxml/lxml.pyclasslookup.pyx => src/lxml/readonlytree.pxi
  • Loading branch information
scoder committed Feb 28, 2008
1 parent 5314268 commit 74960ad
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 150 deletions.
11 changes: 6 additions & 5 deletions doc/element_classes.txt
Expand Up @@ -262,12 +262,10 @@ Taking more elaborate decisions than allowed by the custom scheme is difficult
to achieve in pure Python. It would require access to the tree - before the
elements in the tree have been instantiated as Python Element objects.

Luckily, there is a way to do this. The separate module
``lxml.pyclasslookup`` provides a lookup class called
``PythonElementClassLookup`` that works similar to the custom lookup scheme::
Luckily, there is a way to do this. The ``PythonElementClassLookup``
works similar to the custom lookup scheme::

>>> from lxml.pyclasslookup import PythonElementClassLookup
>>> class MyLookup(PythonElementClassLookup):
>>> class MyLookup(etree.PythonElementClassLookup):
... def lookup(self, document, element):
... return MyElementClass # defined elsewhere

Expand All @@ -293,6 +291,9 @@ provide. Once you have taken the decision which class to use for this
element, you can simply return it and have lxml take care of cleaning up the
instantiated proxy classes.

Note: this lookup scheme originally lived in a separate module called
``lxml.pyclasslookup``.


Implementing namespaces
=======================
Expand Down
82 changes: 81 additions & 1 deletion src/lxml/classlookup.pxi
Expand Up @@ -119,7 +119,7 @@ cdef public class FallbackElementClassLookup(ElementClassLookup) \


################################################################################
# Custom Element class lookup schemes
# default lookup scheme

cdef class ElementDefaultClassLookup(ElementClassLookup):
"""ElementDefaultClassLookup(self, element=None, comment=None, pi=None, entity=None)
Expand Down Expand Up @@ -196,6 +196,10 @@ cdef object _lookupDefaultElementClass(state, _Document _doc, xmlNode* c_node):
else:
assert 0, "Unknown node type: %s" % c_node.type


################################################################################
# attribute based lookup scheme

cdef class AttributeBasedElementClassLookup(FallbackElementClassLookup):
"""AttributeBasedElementClassLookup(self, attribute_name, class_mapping, fallback=None)
Checks an attribute of an Element and looks up the value in a
Expand Down Expand Up @@ -241,6 +245,9 @@ cdef object _attribute_class_lookup(state, _Document doc, xmlNode* c_node):
return lookup._callFallback(doc, c_node)


################################################################################
# per-parser lookup scheme

cdef class ParserBasedElementClassLookup(FallbackElementClassLookup):
"""ParserBasedElementClassLookup(self, fallback=None)
Element class lookup based on the XML parser.
Expand All @@ -256,6 +263,9 @@ cdef object _parser_class_lookup(state, _Document doc, xmlNode* c_node):
return (<FallbackElementClassLookup>state)._callFallback(doc, c_node)


################################################################################
# custom class lookup based on node type, namespace, name

cdef class CustomElementClassLookup(FallbackElementClassLookup):
"""CustomElementClassLookup(self, fallback=None)
Element class lookup based on a subclass method.
Expand Down Expand Up @@ -312,6 +322,76 @@ cdef object _custom_class_lookup(state, _Document doc, xmlNode* c_node):
return lookup._callFallback(doc, c_node)


################################################################################
# read-only tree based class lookup

cdef class PythonElementClassLookup(FallbackElementClassLookup):
"""PythonElementClassLookup(self, fallback=None)
Element class lookup based on a subclass method.
This class lookup scheme allows access to the entire XML tree in
read-only mode. To use it, re-implement the ``lookup(self, doc,
root)`` method in a subclass::
>>> from lxml import etree, pyclasslookup
>>>
>>> class MyElementClass(etree.ElementBase):
... honkey = True
...
>>> class MyLookup(pyclasslookup.PythonElementClassLookup):
... def lookup(self, doc, root):
... if root.tag == "sometag":
... return MyElementClass
... else:
... for child in root:
... if child.tag == "someothertag":
... return MyElementClass
... # delegate to default
... return None
If you return None from this method, the fallback will be called.
The first argument is the opaque document instance that contains
the Element. The second argument is a lightweight Element proxy
implementation that is only valid during the lookup. Do not try
to keep a reference to it. Once the lookup is done, the proxy
will be invalid.
Also, you cannot wrap such a read-only Element in an ElementTree,
and you must take care not to keep a reference to them outside of
the `lookup()` method.
Note that the API of the Element objects is not complete. It is
purely read-only and does not support all features of the normal
`lxml.etree` API (such as XPath, extended slicing or some
iteration methods).
See http://codespeak.net/lxml/element_classes.html
"""
def __init__(self, ElementClassLookup fallback=None):
FallbackElementClassLookup.__init__(self, fallback)
self._lookup_function = _python_class_lookup

def lookup(self, doc, element):
"""lookup(self, doc, element)
Override this method to implement your own lookup scheme.
"""
return None

cdef object _python_class_lookup(state, _Document doc, tree.xmlNode* c_node):
cdef PythonElementClassLookup lookup
cdef _ReadOnlyElementProxy proxy
lookup = <PythonElementClassLookup>state

proxy = _newReadOnlyProxy(None, c_node)
cls = lookup.lookup(doc, proxy)
_freeReadOnlyProxies(proxy)

if cls is not None:
return cls
return lookup._callFallback(doc, c_node)

################################################################################
# Global setup

Expand Down
1 change: 1 addition & 0 deletions src/lxml/lxml.etree.pyx
Expand Up @@ -2567,6 +2567,7 @@ def parse(source, _BaseParser parser=None, *, base_url=None):
include "proxy.pxi" # Proxy handling (element backpointers/memory/etc.)
include "apihelpers.pxi" # Private helper functions
include "xmlerror.pxi" # Error and log handling
include "readonlytree.pxi" # Read-only implementation of Element proxies
include "classlookup.pxi" # Element class lookup mechanisms
include "nsclasses.pxi" # Namespace implementation and registry
include "docloader.pxi" # Support for custom document loaders
Expand Down
3 changes: 3 additions & 0 deletions src/lxml/pyclasslookup.py
@@ -0,0 +1,3 @@
# dummy module for backwards compatibility

from etree import PythonElementClassLookup

0 comments on commit 74960ad

Please sign in to comment.