Skip to content
Snippets Groups Projects
xmlconfig.py 7.17 KiB
Newer Older
# -*- 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")