[Lxml-checkins] r51473 - in lxml/trunk: . src/lxml src/lxml/tests

scoder at codespeak.net scoder at codespeak.net
Thu Feb 14 09:19:44 CET 2008


Author: scoder
Date: Thu Feb 14 09:19:43 2008
New Revision: 51473

Modified:
   lxml/trunk/   (props changed)
   lxml/trunk/src/lxml/lxml.pyclasslookup.pyx
   lxml/trunk/src/lxml/tests/test_pyclasslookup.py
Log:
 r3497 at delle:  sbehnel | 2008-02-14 09:17:23 +0100
 iterchildren() method in lxml.pyclasslookup, faster proxy instantiation


Modified: lxml/trunk/src/lxml/lxml.pyclasslookup.pyx
==============================================================================
--- lxml/trunk/src/lxml/lxml.pyclasslookup.pyx	(original)
+++ lxml/trunk/src/lxml/lxml.pyclasslookup.pyx	Thu Feb 14 09:19:43 2008
@@ -1,9 +1,10 @@
 """
 A whole-tree Element class lookup scheme for `lxml.etree`.
 
-This class lookup scheme allows access to the entire XML tree.  To use
-it, let a class inherit from `PythonElementClassLookup` and
-re-implement the ``lookup(self, doc, root)`` method:
+This class lookup scheme allows access to the entire XML tree in
+read-only mode.  To use it, let a class inherit from
+`PythonElementClassLookup` and re-implement the ``lookup(self, doc,
+root)`` method:
 
     >>> from lxml import etree, pyclasslookup
     >>>
@@ -21,6 +22,15 @@
     ...         # delegate to default
     ...         return None
 
+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).
+
+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.
+
 See http://codespeak.net/lxml/element_classes.html
 """
 
@@ -43,6 +53,7 @@
 __version__ = etree.__version__
 
 cdef class _ElementProxy:
+    "The main read-only Element proxy class (for internal use only!)."
     cdef tree.xmlNode* _c_node
     cdef object _source_proxy
     cdef object _dependent_proxies
@@ -157,6 +168,18 @@
     def __iter__(self):
         return iter(self.getchildren())
 
+    def iterchildren(self, tag=None, *, reversed=False):
+        """iterchildren(self, tag=None, reversed=False)
+
+        Iterate over the children of this element.
+        """
+        children = self.getchildren()
+        if tag is not None:
+            children = [ el for el in children if el.tag == tag ]
+        if reversed:
+            children = children[::-1]
+        return iter(children)
+
     def get(self, key, default=None):
         """Gets an element attribute.
         """
@@ -230,15 +253,21 @@
             return _newProxy(self._source_proxy, c_node)
         return None
 
+
+cdef extern from "etree_defs.h":
+    # macro call to 't->tp_new()' for fast instantiation
+    cdef _ElementProxy NEW_PROXY "PY_NEW" (object t)
+
 cdef _ElementProxy _newProxy(_ElementProxy sourceProxy, tree.xmlNode* c_node):
     cdef _ElementProxy el
-    el = _ElementProxy()
+    el = NEW_PROXY(_ElementProxy)
     el._c_node = c_node
     if sourceProxy is None:
-        sourceProxy = el
-        el._dependent_proxies = []
-    el._source_proxy = sourceProxy
-    python.PyList_Append(sourceProxy._dependent_proxies, el)
+        el._source_proxy = el
+        el._dependent_proxies = [el]
+    else:
+        el._source_proxy = sourceProxy
+        python.PyList_Append(sourceProxy._dependent_proxies, el)
     return el
 
 cdef _freeProxies(_ElementProxy sourceProxy):

Modified: lxml/trunk/src/lxml/tests/test_pyclasslookup.py
==============================================================================
--- lxml/trunk/src/lxml/tests/test_pyclasslookup.py	(original)
+++ lxml/trunk/src/lxml/tests/test_pyclasslookup.py	Thu Feb 14 09:19:43 2008
@@ -259,6 +259,43 @@
         self.assertEquals([ c.tag for c in root.getchildren() ],
                           child_tags)
 
+    def test_lookup_iterchildren(self):
+        el_class = self._buildElementClass()
+        el_class.CHILD_TAGS = None
+        def lookup(doc, el):
+            if el_class.CHILD_TAGS is None:
+                el_class.CHILD_TAGS = [ c.tag for c in el.iterchildren() ]
+            return el_class
+        self._setClassLookup(lookup)
+        root = self.XML(xml_str)
+        child_tags = root.CHILD_TAGS
+        self.assertNotEquals(None, child_tags)
+        self.assertEquals([ c.tag for c in root.getchildren() ],
+                          child_tags)
+
+    def test_lookup_iterchildren_tag(self):
+        el_class = self._buildElementClass()
+        el_class.CHILD_TAGS = None
+        def lookup(doc, el):
+            if not el_class.CHILD_TAGS:
+                el_class.CHILD_TAGS = [
+                    c.tag for c in el.iterchildren(tag='{objectified}c2') ]
+            return el_class
+        self._setClassLookup(lookup)
+
+        root = self.XML(xml_str)
+        child_tags = root.CHILD_TAGS
+        self.assertNotEquals(None, child_tags)
+        self.assertEquals([], child_tags)
+
+        c1 = root[0]
+        child_tags = root.CHILD_TAGS
+        self.assertNotEquals(None, child_tags)
+        self.assertNotEquals([], child_tags)
+        self.assertEquals(
+            [ c.tag for c in root[0].iterchildren(tag='{objectified}c2') ],
+            child_tags)
+
     def test_lookup_getparent(self):
         el_class = self._buildElementClass()
         el_class.PARENT = None


More information about the lxml-checkins mailing list