/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
PhysicsTools/PythonAnalysis/python/XML2Python.py
182 строки
6 KB
David
python 2to3 tool lib2to3.fixes.fix_basestring
03 июн 2018, 20:48
03 июн 2018, 20:48
1c7e3fe
Код
Авторство
О чём код?
## Original version of code heavily based on recipe written by Wai Yip ## Tung, released under PSF license. ## http://code.activestate.com/recipes/534109/ import re import os import xml.sax.handler class DataNode (object): def __init__ (self, **kwargs): self._attrs = {} # XML attributes and child elements self._data = None # child text data self._ncDict = kwargs.get ('nameChangeDict', {}) def __len__ (self): # treat single element as a list of 1 return 1 def __getitem__ (self, key): if isinstance (key, str): return self._attrs.get(key,None) else: return [self][key] def __contains__ (self, name): return name in self._attrs def __nonzero__ (self): return bool (self._attrs or self._data) def __getattr__ (self, name): if name.startswith('__'): # need to do this for Python special methods??? raise AttributeError (name) return self._attrs.get (name, None) def _add_xml_attr (self, name, value): change = self._ncDict.get (name) if change: name = change if name in self._attrs: # multiple attribute of the same name are represented by a list children = self._attrs[name] if not isinstance(children, list): children = [children] self._attrs[name] = children children.append(value) else: self._attrs[name] = value def __str__ (self): return self._data or '' def __repr__ (self): items = sorted (self._attrs.items()) if self._data: items.append(('data', self._data)) return u'{%s}' % ', '.join([u'%s:%s' % (k,repr(v)) for k,v in items]) def attributes (self): return self._attrs class TreeBuilder (xml.sax.handler.ContentHandler): non_id_char = re.compile('[^_0-9a-zA-Z]') def __init__ (self, **kwargs): self._stack = [] self._text_parts = [] self._ncDict = kwargs.get ('nameChangeDict', {}) self._root = DataNode (nameChangeDict = self._ncDict) self.current = self._root def startElement (self, name, attrs): self._stack.append( (self.current, self._text_parts)) self.current = DataNode (nameChangeDict = self._ncDict) self._text_parts = [] # xml attributes --> python attributes for k, v in attrs.items(): self.current._add_xml_attr (TreeBuilder._name_mangle(k), v) def endElement (self, name): text = ''.join (self._text_parts).strip() if text: self.current._data = text if self.current.attributes(): obj = self.current else: # a text only node is simply represented by the string obj = text or '' self.current, self._text_parts = self._stack.pop() self.current._add_xml_attr (TreeBuilder._name_mangle(name), obj) def characters (self, content): self._text_parts.append(content) def root (self): return self._root def topLevel (self): '''Returns top level object''' return self._root.attributes().values()[0] @staticmethod def _name_mangle (name): return TreeBuilder.non_id_char.sub('_', name) regexList = [ (re.compile (r'&'), '&' ), (re.compile (r'<'), '<' ), (re.compile (r'>'), '>' ), (re.compile (r'"'), '"e;' ), (re.compile (r"'"), ''' ) ] quoteRE = re.compile (r'(\w\s*=\s*")([^"]+)"') def fixQuoteValue (match): '''Changes all characters inside of the match''' quote = match.group(2) for regexTup in regexList: quote = regexTup[0].sub( regexTup[1], quote ) return match.group(1) + quote + '"' def xml2obj (**kwargs): ''' Converts XML data into native Python object. Takes either file handle or string as input. Does NOT fix illegal characters. input source: Exactly one of the three following is needed filehandle - input from file handle contents - input from string filename - input from filename options: filtering - boolean value telling code whether or not to fileter input selection to remove illegal XML characters nameChangeDict - dictionaries of names to change in python object''' # make sure we have exactly 1 input source filehandle = kwargs.get ('filehandle') contents = kwargs.get ('contents') filename = kwargs.get ('filename') if not filehandle and not contents and not filename: raise RuntimeError("You must provide 'filehandle', 'contents', or 'filename'") if filehandle and contents or \ filehandle and filename or \ contents and filename: raise RuntimeError("You must provide only ONE of 'filehandle', 'contents', or 'filename'") # are we filtering? filtering = kwargs.get ('filtering') if filtering: # if we are filtering, we need to read in the contents to modify them if not contents: if not filehandle: try: filehandle = open (filename, 'r') except: raise RuntimeError("Failed to open '%s'" % filename) contents = '' for line in filehandle: contents += line filehandle.close() filehandle = filename = '' contents = quoteRE.sub (fixQuoteValue, contents) ncDict = kwargs.get ('nameChangeDict', {}) builder = TreeBuilder (nameChangeDict = ncDict) if contents: xml.sax.parseString(contents, builder) else: if not filehandle: try: filehandle = open (filename, 'r') except: raise RuntimeError("Failed to open '%s'" % filename) xml.sax.parse(filehandle, builder) return builder.topLevel()