# -*- coding: utf-8 -*- dbg_ = False import sys from xml.dom import minidom from UserDict import UserDict #rom collections import namedtuple import traceback class InvalidFileError(Exception): def __init__(self, value): self.message = value def __str__(self): return repr(self.message) import urllib import StringIO def open_anything(source): """URI, filename, or string --> stream This function lets you define parsers that take any input source (URL, pathname to local or network file, or actual data as a string) and deal with it in a uniform manner. Returned object is guaranteed to have all the basic stdio read methods (read, readline, readlines). Just .close() the object when you're done with it. Examples:: >>> from xml.dom import minidom >>> sock = open_anything("http://localhost/kant.xml") >>> doc = minidom.parse(sock) >>> sock.close() >>> sock = open_anything("c:\\inetpub\\wwwroot\\kant.xml") >>> doc = minidom.parse(sock) >>> sock.close() >>> sock = open_anything("<ref id='conjunction'><text>and</text><text>or</text></ref>") >>> doc = minidom.parse(sock) >>> sock.close() """ if hasattr(source, "read"): return source if source == '-': return sys.stdin # try to open with urllib (if source is http, ftp, or file URL) try: return urllib.urlopen(source) except (IOError, OSError): pass # try to open with native open function (if source is pathname) try: return open(source) except (IOError, OSError): pass # treat source as string return StringIO.StringIO(str(source)) def _get_text(nodelist): """ Extract an string from a xml node data.""" rc_ = [node.data for node in nodelist if node.nodeType == node.TEXT_NODE] return ''.join(rc_).strip().encode('ascii') def _get_value(node, tagname): """ Extract the value from an xml node""" values = node.getElementsByTagName(tagname) if len(values) == 0: return '' internal_node = values[0] return _get_text(internal_node.childNodes) READ_ONLY = 0 READ_WRITE = 1 WRITE_ONLY = 2 IS_COMMAND = 3 class XmlItem: def __init__(self, flag , type, handler, name, tango_name, description="", default=None, dimension = 1, memorized = 0 , read_function = '' , write_function = ''): self.flag = flag self.type = type self.handler = handler self.tango_name = tango_name self.name = name self.description = description self.default = default self.dimension = dimension self.memorized = memorized self.read_function = read_function self.write_function = write_function def __str__(self): return "Attr %s = %s/%s \n %s \n %s %d \n %s \n %s"% (self.name, self.handler, self.name, self.description, self.default, self.memorized, self.read_function, self.write_function) class ScriptXmlConfig: """ Parser of the XML file in python usefull class attributes a dict with: - flag: read_only, write_only, read_write - type: short, double, string, - handler: tango attribute associated - name: name or label of this attribute - description: information for the attribute - memorized: uses Tango Memorize feature, available only for scalar attributes - default: default value ( WARNING: is loaded using eval() ) - read_function: name of the function that will be executed for every read operation - write_function: name of the function that will be executed for every write operation """ def __init__(self, filename): self.entries = dict() self.doc = self._load(filename) self._parse() def __str__(self): return "DaqXmlConfig %s %s"% (str(self.attributes)) def _parse(self): """Parse the xml file""" try: self.handle_entries(self.doc.getElementsByTagName("ATTRIBUTES_RO"),flag=READ_ONLY) self.handle_entries(self.doc.getElementsByTagName("ATTRIBUTES_RW"),flag=READ_WRITE) self.handle_entries(self.doc.getElementsByTagName("ATTRIBUTES_WO"),flag=WRITE_ONLY) self.handle_entries(self.doc.getElementsByTagName("COMMANDS"),flag=IS_COMMAND) except IndexError: traceback.print_exc() raise InvalidFileError( "Failed to parse the configuration file") @classmethod def _load(cls, source): """load XML input source, return parsed XML document - a URL of a remote XML file ("http://diveintopython.org/kant.xml") - a filename of a local XML file ("~/diveintopython/common/py/kant.xml") - standard input ("-") - the actual XML document, as a string """ sock = open_anything(source) try: xmldoc = minidom.parse(sock).documentElement except Exception, ex: raise InvalidFileError(str(ex)) sock.close() return xmldoc def handle_entries(self, elements, flag): for group_of_attributes in elements: attributes = [attribute for attribute in group_of_attributes.childNodes if attribute.nodeType == 1] for attribute in attributes: type = _get_value(attribute, 'TYPE') handler = _get_value(attribute,'HANDLER') attr = handler +'/' + _get_value(attribute, 'TANGONAME') name = attribute.nodeName desc =_get_value(attribute, 'DESCRIPTION') dimension_s = _get_value(attribute, 'DIMENSION') if dimension_s == '': dimension = 1 elif dimension_s.find('(')>= 0: dimension = eval(dimension_s) else: dimension = int(dimension_s) memorized_s = _get_value(attribute, 'MEMORIZED') if memorized_s == '1' and dimension == 1 : memorized = 1 else : memorized = 0 # default_v = _get_value(attribute, 'DEFAULT') # read_function = _get_value(attribute, 'READ_FUNCTION') write_function = _get_value(attribute, 'WRITE_FUNCTION') # attr_entry = XmlItem(flag, type,handler,name,attr,desc,default_v,dimension,memorized,read_function,write_function) if dbg_: print attr_entry self.entries[attr_entry.name] = attr_entry if __name__ == "__main__": xml = ScriptXmlConfig("./scripts/ldm_daq_conf.xml")