configurationengine/source/cone/public/_etree_wrapper.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
child 5 d2c80f5cab53
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
    30         raise NotImplementedError()
    30         raise NotImplementedError()
    31     
    31     
    32     def get_lineno(self, element):
    32     def get_lineno(self, element):
    33         raise NotImplementedError()
    33         raise NotImplementedError()
    34 
    34 
       
    35     def get_elem_from_lineno(self, root, lineno):
       
    36         raise NotImplementedError()
       
    37 
    35 class ElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
    38 class ElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
    36     
    39 
    37     class CustomTreeBuilder(ElementTree.TreeBuilder):
    40     class CustomTreeBuilder(ElementTree.TreeBuilder):
    38         """
    41         """
    39         Custom TreeBuilder for ElementTree that records line numbers
    42         Custom TreeBuilder for ElementTree that records line numbers
    40         of the elements.
    43         of the elements.
    41         """
    44         """
    42         def start(self, tag, attrs):
    45         def start(self, tag, attrs):
    43             elem = ElementTree.TreeBuilder.start(self, tag, attrs)
    46             elem = ElementTree.TreeBuilder.start(self, tag, attrs)
    44             lineno = self._xmltreebuilder._parser.CurrentLineNumber
    47             lineno = self._xmltreebuilder._parser.CurrentLineNumber
    45             #print "Tag: %s, line: %r" % (tag, lineno)
    48             # print "Tag: %s, line: %r" % (tag, lineno)
    46             elem.sourceline = lineno
    49             elem.sourceline = lineno
    47             return elem
    50             return elem
    48     
    51     
    49     def get_module(self):
    52     def get_module(self):
    50         return ElementTree
    53         return ElementTree
    53         try:
    56         try:
    54             treebuilder = self.CustomTreeBuilder()
    57             treebuilder = self.CustomTreeBuilder()
    55             parser = ElementTree.XMLTreeBuilder(target=treebuilder)
    58             parser = ElementTree.XMLTreeBuilder(target=treebuilder)
    56             treebuilder._xmltreebuilder = parser
    59             treebuilder._xmltreebuilder = parser
    57             parser.feed(text)
    60             parser.feed(text)
    58             return parser.close()
    61             self.root = parser.close()
       
    62             return self.root
    59         except expat.ExpatError, e:
    63         except expat.ExpatError, e:
    60             raise exceptions.XmlParseError(
    64             raise exceptions.XmlParseError(
    61                 "XML parse error on line %d: %s" % (e.lineno, e),
    65                 "XML parse error on line %d: %s" % (e.lineno, e),
    62                 e.lineno, str(e))
    66                 e.lineno, str(e))
    63     
    67     
    64     def tostring(self, etree, encoding=None):
    68     def tostring(self, etree, encoding=None):
    65         return ElementTree.tostring(etree, encoding)
    69         return ElementTree.tostring(etree, encoding)
    66     
    70     
    67     def get_lineno(self, element):
    71     def get_lineno(self, element):
    68         return element.sourceline
    72         try:
    69 
    73             return element.sourceline
       
    74         except AttributeError:
       
    75             return None
       
    76 
       
    77     def get_elem_from_lineno(self, root, lineno):
       
    78         for elem in root.getiterator():
       
    79             if elem.sourceline == lineno:
       
    80                 return elem
       
    81         return None
    70 
    82 
    71 class CElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
    83 class CElementTreeBackendWrapper(ElementTreeBackendWrapperBase):
    72     def __init__(self):
    84     def __init__(self):
    73         try:
    85         try:
    74             from cElementTree import cElementTree
    86             from cElementTree import cElementTree
    80     def get_module(self):
    92     def get_module(self):
    81         return self.cElementTree
    93         return self.cElementTree
    82     
    94     
    83     def fromstring(self, text):
    95     def fromstring(self, text):
    84         try:
    96         try:
    85             return self.cElementTree.fromstring(text)
    97             self.root = self.cElementTree.fromstring(text)
       
    98             return self.root
    86         except SyntaxError, e:
    99         except SyntaxError, e:
    87             # cElementTree raises a SyntaxError, but does not set
   100             # cElementTree raises a SyntaxError, but does not set
    88             # its lineno attribute, so look for the line number
   101             # its lineno attribute, so look for the line number
    89             # in the exception text
   102             # in the exception text
    90             import re
   103             import re
   101     
   114     
   102     def get_lineno(self, element):
   115     def get_lineno(self, element):
   103         # cElementTree does not support line numbers
   116         # cElementTree does not support line numbers
   104         return None
   117         return None
   105 
   118 
       
   119     def get_elem_from_lineno(self, root, lineno):
       
   120         # cElementTree does not support line numbers
       
   121         return None
   106 
   122 
   107 class LxmlBackendWrapper(ElementTreeBackendWrapperBase):
   123 class LxmlBackendWrapper(ElementTreeBackendWrapperBase):
   108     
   124     
   109     def __init__(self):
   125     def __init__(self):
   110         import lxml.etree
   126         import lxml.etree
   113     def get_module(self):
   129     def get_module(self):
   114         return self.lxml.etree
   130         return self.lxml.etree
   115     
   131     
   116     def fromstring(self, text):
   132     def fromstring(self, text):
   117         try:
   133         try:
   118             elem = self.lxml.etree.fromstring(text)
   134             self.root = self.lxml.etree.fromstring(text)
   119             
   135             self.remove_comments(self.root)
   120             # lxml parses also comments, but ConE does not expect those,
   136             return self.root
   121             # so remove them to prevent any errors on that account
       
   122             def remove_comments(elem):
       
   123                 # Find the comments under this element
       
   124                 comments = []
       
   125                 for x in elem:
       
   126                     if isinstance(x, self.lxml.etree._Comment):
       
   127                         comments.append(x)
       
   128                 
       
   129                 # Remove them
       
   130                 for c in comments:
       
   131                     elem.remove(c)
       
   132                 
       
   133                 # Recurse to sub-elements
       
   134                 for subelem in elem:
       
   135                     remove_comments(subelem)
       
   136             
       
   137             remove_comments(elem)
       
   138             
       
   139             return elem
       
   140         except self.lxml.etree.XMLSyntaxError, e:
   137         except self.lxml.etree.XMLSyntaxError, e:
   141             raise exceptions.XmlParseError(
   138             raise exceptions.XmlParseError(
   142                 "XML parse error on line %d: %s" % (e.position[0], e),
   139                 "XML parse error on line %d: %s" % (e.position[0], e),
   143                 e.position[0], str(e))
   140                 e.position[0], str(e))
   144     
   141     
       
   142     def remove_comments(self, elem):
       
   143         """
       
   144         lxml parses also comments, but ConE does not expect those,
       
   145         so remove them to prevent any errors on that account
       
   146         """
       
   147         # Find the comments under this element
       
   148         comments = []
       
   149         for x in elem:
       
   150             if isinstance(x, self.lxml.etree._Comment):
       
   151                 comments.append(x)
       
   152         
       
   153         # Remove them
       
   154         for c in comments:
       
   155             elem.remove(c)
       
   156         
       
   157         # Recurse to sub-elements
       
   158         for subelem in elem:
       
   159             self.remove_comments(subelem)
       
   160             
   145     def tostring(self, etree, encoding=None):
   161     def tostring(self, etree, encoding=None):
   146         return self.lxml.etree.tostring(etree, encoding=encoding)
   162         return self.lxml.etree.tostring(etree, encoding=encoding)
   147     
   163     
   148     def get_lineno(self, element):
   164     def get_lineno(self, element):
   149         return element.sourceline
   165         try:
   150 
   166             return element.sourceline
       
   167         except AttributeError:
       
   168             return None
       
   169 
       
   170     def get_elem_from_lineno(self, root, lineno):
       
   171         for elem in root.getiterator():
       
   172             if elem.sourceline == lineno:
       
   173                 return elem
       
   174         return None
       
   175     
   151 # ============================================================================
   176 # ============================================================================
   152 #
   177 #
   153 # ============================================================================
   178 # ============================================================================
   154 
   179 
   155 class ElementTreeWrapper(object):
   180 class ElementTreeWrapper(object):
   165     BACKEND_LXML             = 'lxml'
   190     BACKEND_LXML             = 'lxml'
   166     
   191     
   167     # Import order for the default back-end. The list is traversed
   192     # Import order for the default back-end. The list is traversed
   168     # top-down and the first back-end whose importing is successful is
   193     # top-down and the first back-end whose importing is successful is
   169     # used as the default back-end
   194     # used as the default back-end
   170     DEFAULT_BACKEND_IMPORT_ORDER = [BACKEND_C_ELEMENT_TREE,
   195     DEFAULT_BACKEND_IMPORT_ORDER = [BACKEND_LXML,
       
   196                                     BACKEND_C_ELEMENT_TREE,
   171                                     BACKEND_ELEMENT_TREE]
   197                                     BACKEND_ELEMENT_TREE]
   172     
   198     
   173     _backend_mapping = {BACKEND_ELEMENT_TREE:     ElementTreeBackendWrapper,
   199     _backend_mapping = {BACKEND_ELEMENT_TREE:     ElementTreeBackendWrapper,
   174                         BACKEND_C_ELEMENT_TREE:   CElementTreeBackendWrapper,
   200                         BACKEND_C_ELEMENT_TREE:   CElementTreeBackendWrapper,
   175                         BACKEND_LXML:             LxmlBackendWrapper}
   201                         BACKEND_LXML:             LxmlBackendWrapper}
   227         Note that for the cElementTree parser this will always return
   253         Note that for the cElementTree parser this will always return
   228         None, since that parser does not support line numbers.
   254         None, since that parser does not support line numbers.
   229         """
   255         """
   230         return self._get_backend().get_lineno(element)
   256         return self._get_backend().get_lineno(element)
   231     
   257     
       
   258     def get_elem_from_lineno(self, root, lineno):
       
   259         """
       
   260         Return the element from the given line number of the given XML element.
       
   261         
       
   262         @param root: the root element to search from
       
   263         @param lineno: the line number to search for  
       
   264         
       
   265         Note that for the cElementTree parser this will always return
       
   266         None, since that parser does not support line numbers.
       
   267         """
       
   268         return self._get_backend().get_elem_from_lineno(root, lineno)
       
   269 
   232     def __getattribute__(self, attrname):
   270     def __getattribute__(self, attrname):
   233         try:
   271         try:
   234             # Try to get the attribute from this object (the top-level wrapper)
   272             # Try to get the attribute from this object (the top-level wrapper)
   235             return object.__getattribute__(self, attrname)
   273             return object.__getattribute__(self, attrname)
   236         except AttributeError:
   274         except AttributeError: