configurationengine/source/cone/public/_etree_wrapper.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
child 5 d2c80f5cab53
--- a/configurationengine/source/cone/public/_etree_wrapper.py	Fri Mar 12 08:30:17 2010 +0200
+++ b/configurationengine/source/cone/public/_etree_wrapper.py	Tue Aug 10 14:29:28 2010 +0300
@@ -32,8 +32,11 @@
     def get_lineno(self, element):
         raise NotImplementedError()
 
+    def get_elem_from_lineno(self, root, lineno):
+        raise NotImplementedError()
+
 class ElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
-    
+
     class CustomTreeBuilder(ElementTree.TreeBuilder):
         """
         Custom TreeBuilder for ElementTree that records line numbers
@@ -42,7 +45,7 @@
         def start(self, tag, attrs):
             elem = ElementTree.TreeBuilder.start(self, tag, attrs)
             lineno = self._xmltreebuilder._parser.CurrentLineNumber
-            #print "Tag: %s, line: %r" % (tag, lineno)
+            # print "Tag: %s, line: %r" % (tag, lineno)
             elem.sourceline = lineno
             return elem
     
@@ -55,7 +58,8 @@
             parser = ElementTree.XMLTreeBuilder(target=treebuilder)
             treebuilder._xmltreebuilder = parser
             parser.feed(text)
-            return parser.close()
+            self.root = parser.close()
+            return self.root
         except expat.ExpatError, e:
             raise exceptions.XmlParseError(
                 "XML parse error on line %d: %s" % (e.lineno, e),
@@ -65,8 +69,16 @@
         return ElementTree.tostring(etree, encoding)
     
     def get_lineno(self, element):
-        return element.sourceline
+        try:
+            return element.sourceline
+        except AttributeError:
+            return None
 
+    def get_elem_from_lineno(self, root, lineno):
+        for elem in root.getiterator():
+            if elem.sourceline == lineno:
+                return elem
+        return None
 
 class CElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
     def __init__(self):
@@ -82,7 +94,8 @@
     
     def fromstring(self, text):
         try:
-            return self.cElementTree.fromstring(text)
+            self.root = self.cElementTree.fromstring(text)
+            return self.root
         except SyntaxError, e:
             # cElementTree raises a SyntaxError, but does not set
             # its lineno attribute, so look for the line number
@@ -103,6 +116,9 @@
         # cElementTree does not support line numbers
         return None
 
+    def get_elem_from_lineno(self, root, lineno):
+        # cElementTree does not support line numbers
+        return None
 
 class LxmlBackendWrapper(ElementTreeBackendWrapperBase):
     
@@ -115,39 +131,48 @@
     
     def fromstring(self, text):
         try:
-            elem = self.lxml.etree.fromstring(text)
-            
-            # lxml parses also comments, but ConE does not expect those,
-            # so remove them to prevent any errors on that account
-            def remove_comments(elem):
-                # Find the comments under this element
-                comments = []
-                for x in elem:
-                    if isinstance(x, self.lxml.etree._Comment):
-                        comments.append(x)
-                
-                # Remove them
-                for c in comments:
-                    elem.remove(c)
-                
-                # Recurse to sub-elements
-                for subelem in elem:
-                    remove_comments(subelem)
-            
-            remove_comments(elem)
-            
-            return elem
+            self.root = self.lxml.etree.fromstring(text)
+            self.remove_comments(self.root)
+            return self.root
         except self.lxml.etree.XMLSyntaxError, e:
             raise exceptions.XmlParseError(
                 "XML parse error on line %d: %s" % (e.position[0], e),
                 e.position[0], str(e))
     
+    def remove_comments(self, elem):
+        """
+        lxml parses also comments, but ConE does not expect those,
+        so remove them to prevent any errors on that account
+        """
+        # Find the comments under this element
+        comments = []
+        for x in elem:
+            if isinstance(x, self.lxml.etree._Comment):
+                comments.append(x)
+        
+        # Remove them
+        for c in comments:
+            elem.remove(c)
+        
+        # Recurse to sub-elements
+        for subelem in elem:
+            self.remove_comments(subelem)
+            
     def tostring(self, etree, encoding=None):
         return self.lxml.etree.tostring(etree, encoding=encoding)
     
     def get_lineno(self, element):
-        return element.sourceline
+        try:
+            return element.sourceline
+        except AttributeError:
+            return None
 
+    def get_elem_from_lineno(self, root, lineno):
+        for elem in root.getiterator():
+            if elem.sourceline == lineno:
+                return elem
+        return None
+    
 # ============================================================================
 #
 # ============================================================================
@@ -167,7 +192,8 @@
     # Import order for the default back-end. The list is traversed
     # top-down and the first back-end whose importing is successful is
     # used as the default back-end
-    DEFAULT_BACKEND_IMPORT_ORDER = [BACKEND_C_ELEMENT_TREE,
+    DEFAULT_BACKEND_IMPORT_ORDER = [BACKEND_LXML,
+                                    BACKEND_C_ELEMENT_TREE,
                                     BACKEND_ELEMENT_TREE]
     
     _backend_mapping = {BACKEND_ELEMENT_TREE:     ElementTreeBackendWrapper,
@@ -229,6 +255,18 @@
         """
         return self._get_backend().get_lineno(element)
     
+    def get_elem_from_lineno(self, root, lineno):
+        """
+        Return the element from the given line number of the given XML element.
+        
+        @param root: the root element to search from
+        @param lineno: the line number to search for  
+        
+        Note that for the cElementTree parser this will always return
+        None, since that parser does not support line numbers.
+        """
+        return self._get_backend().get_elem_from_lineno(root, lineno)
+
     def __getattribute__(self, attrname):
         try:
             # Try to get the attribute from this object (the top-level wrapper)