[Checkins] SVN: Sandbox/malthe/chameleon.core/ Do not use XPath during compilation if lxml is not available.

Malthe Borch mborch at gmail.com
Mon Dec 1 10:30:52 EST 2008


Log message for revision 93488:
  Do not use XPath during compilation if lxml is not available.

Changed:
  U   Sandbox/malthe/chameleon.core/CHANGES.txt
  U   Sandbox/malthe/chameleon.core/src/chameleon/core/etree.py
  U   Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py

-=-
Modified: Sandbox/malthe/chameleon.core/CHANGES.txt
===================================================================
--- Sandbox/malthe/chameleon.core/CHANGES.txt	2008-12-01 12:44:06 UTC (rev 93487)
+++ Sandbox/malthe/chameleon.core/CHANGES.txt	2008-12-01 15:30:52 UTC (rev 93488)
@@ -4,6 +4,9 @@
 HEAD
 ~~~~
 
+- Do not use XPath-expressions during compilation if lxml is not
+  available. [malthe]
+
 - Ensure argument uniqueness for macro functions over the combined set of
   scope and keyword arguments. [hannosch]
 

Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/etree.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/etree.py	2008-12-01 12:44:06 UTC (rev 93487)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/etree.py	2008-12-01 15:30:52 UTC (rev 93488)
@@ -63,6 +63,17 @@
 
     XMLSyntaxError = lxml.etree.XMLSyntaxError
 
+    def elements_with_attribute(element, ns, name, value=None):
+        if value is None:
+            expression = './/*[@prefix:%s] | .//prefix:*[@%s]' % (name, name)
+        else:
+            expression = './/*[@prefix:%s="%s"] | .//prefix:*[@%s="%s"]' % (
+                name, value, name, value)
+            
+        return element.xpath(
+            expression,
+            namespaces={'prefix': ns})
+
     class BufferIO(list):
         write = list.append
 
@@ -229,13 +240,23 @@
 except ImportError:
     ET = import_elementtree()
 
-    try:
-        from pdis.xpath import XPath
-    except ImportError:
-        raise ImportError("PDIS-XPath is required when lxml is unavailable.")
+    XMLSyntaxError = SyntaxError
 
-    XMLSyntaxError = ET.XMLSyntaxError
-    
+    def elements_with_attribute(element, ns, name, value=None):
+        attributes = utils.get_attributes_from_namespace(
+            element, ns)
+
+        if value is not None:
+            if value in (
+                attributes.get(name), attributes.get('{%s}%s' % (ns, name))):
+                yield element
+        elif 'name' in attributes or '{%s}%s' % (ns, name) in attributes:
+            yield element
+            
+        for child in element:
+            for match in elements_with_attribute(child, ns, name):
+                yield match
+            
     class ElementBase(object, ET._ElementInterface):
         _parent = None
         
@@ -268,8 +289,8 @@
             return ET.tostring(self)
 
         def xpath(self, path, namespaces={}):
-            xpath = XPath(path, namespace_mapping=namespaces)
-            return xpath.evaluate(self)
+            raise NotImplementedError(
+                "No XPath-engine available.")
             
         @property
         def nsmap(self):
@@ -335,7 +356,7 @@
         def handle_cdata_end(self):
             self._target.end(utils.xhtml_attr('cdata'))
             
-    def parse(body, element_mapping):
+    def parse(body, element_mapping, fallback=None):
         def element_factory(tag, attrs=None, nsmap=None):
             if attrs is None:
                 attrs = {}
@@ -348,7 +369,7 @@
                 ns_tag = None
 
             namespace = element_mapping[ns]
-            factory = namespace.get(ns_tag) or namespace.get(None) or ElementBase
+            factory = namespace.get(ns_tag) or namespace.get(None) or fallback
 
             element = object.__new__(factory)
             element.__init__(tag, attrs)
@@ -359,6 +380,7 @@
         parser = XMLParser(target=target)
         parser.entity = dict([(name, "&%s;" % name) for name in htmlentitydefs.entitydefs])
         parser.feed(body)
+
         root = parser.close()
 
         return root, parser.doctype

Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py	2008-12-01 12:44:06 UTC (rev 93487)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py	2008-12-01 15:30:52 UTC (rev 93488)
@@ -372,9 +372,8 @@
             # for each fill-slot element, create a new output stream
             # and save value in a temporary variable
             kwargs = []
-            for element in self.element.xpath(
-                './/*[@metal:fill-slot] | .//metal:*[@fill-slot]',
-                namespaces={'metal': config.METAL_NS}):
+            for element in etree.elements_with_attribute(
+                self.element, config.METAL_NS, 'fill-slot'):
                 if element.node.fill_slot is None:
                     # XXX this should not be necessary, but the above
                     # xpath expression finds non-"metal:fill-slot"
@@ -691,10 +690,8 @@
         # if macro is non-trivial, start compilation at the element
         # where the macro is defined
         if macro:
-            elements = self.root.xpath(
-                'descendant-or-self::*[@metal:define-macro="%s"] |'
-                'descendant-or-self::metal:*[@define-macro="%s"]' % (macro, macro),
-                namespaces={'metal': config.METAL_NS})
+            elements = tuple(etree.elements_with_attribute(
+                self.root, config.METAL_NS, 'define-macro', macro))
 
             if not elements:
                 raise ValueError("Macro not found: %s." % macro)
@@ -855,8 +852,11 @@
             return selectors
 
         self._selectors = selectors = {}
-        for element in self.tree.xpath(
-            './/*[@meta:select]', namespaces={'meta': config.META_NS}):
+
+        elements = etree.elements_with_attribute(
+            self.tree, config.META_NS, 'select')
+
+        for element in elements:
             name = element.attrib[utils.meta_attr('select')]
             selectors[name] = element.xpath
 



More information about the Checkins mailing list