Python library with tools for analysis of FESA XML files
Usage:
from pylib.fesa import xmlfesatools
The library contains functions and classes to navigate in FESA XML files, mainly instance files but also design files. In addition, it contains tools to fetch files from the FESA web-server.
== PAGE UNDER DEVELOPMENT ==
Class XmlFile
: Abstraction of FESA XML-Structures
The class
XmlFile
represents FESA XML-files. It provides methods to navigate in the XML-tree and a method to write the XML-tree back to disk. Specifics of FESA instance files and FESA design files are handled in subclasses
xmlfesatools.XmlInstFile
(
see here) and
xmlfesatools.XmlDesignFile
(
see here).
The
fesatools.XmlFile
internally uses the Python
lxml.etree
toolset. The
fesatools.XmlFile
class holds the XML content as a
lxml.etree._ElementTree
element tree, which is available by the method
get_inst_tree()
. The method
get_root_element()
returns the root element of this tree.
Navigating in XmlFile
Objects
Representation of Hierarchy by Path-Strings
The
xmlfesatools.XmlFile
class provides methods to navigate in the element tree. These methods operate with path-variables (strings). They represent the XML hierarchy, separating the elements by dots. The string
"child1.child2"
means, starting with the root element, the child element with name
child1
and its child element with the name
child2
. The root element of this relative path is given by the
!baseElement
parameter, which is the
lxml.etree.Element
root of the relative XML tree. The default value for
!baseElement
is the root element of the XML file.
For access to nodes in the XML-tree, three methods are provided:
get_element(path, baseElement=None)= return =lxml.etree.Element according to path
get_all_elements(path, baseElement=None)= return all =lxml.etree.Element matching the path
parameter
get_path(element, baseElement=None)= return path of the =lxml.etree.Element, relative to the root element baseElement
Path elements may be nested to any level. Given
<root-element>
<parent>
<child>
<grandchild>
</grandchild>
</child>
</parent>
</root-element>
The sub node (<grandchild>) is accessed by the location string "parent.child.grandchild", which is relative to the root-element (unless otherwise given):
grandchild_node = get_element("parent.child.grandchild")
Identification of Elements with Attributes
Often an XML element has child nodes with identical tag names, which are identified by different attribute values, like
<root-element>
<parent>
<child name="AAA">
</child>
<child name="BBB">
<grandchild name="XXX"/>
<grandchild name="YYY"/>
</child>
<child name="CCC">
</child>
</parent>
</root-element>
Such child nodes can be accessed by given the attribute name and value in paranthesis, like
child_node1 = get_element("parent.child[name=AAA]")
grandchild_node = get_element("parent.child[name=BBB].grandchild[name=XXX]")
Attribute names "name" can be omitted- The following two commands are equivalent to the upper ones:
child_node1 = get_element("parent.child[AAA]")
grandchild_node = get_element("parent.child[BBB].grandchild[XXX]")
Abbreviation of Path-Strings
Names in the path string can be abbreviated. Only the leading part of the tag's name has to be specified. Given only
'info'
will find a tag like
<information>
. If a name matches, it is prefered. Given
'accelerator'
will find <accelerator> if both tags
<accelerator>
and
<acceleratorZone>
exist, while only
'accelerato'
will result in a
multiple elements found
error.
As an example, given a
xmlfesatools.XmlInstFile
inst
, containing a node
information
as
<information>= =<fesa-version>7.0.0</fesa-version>
</information>
a call of get_element('information.fesa') will return the
lxml.etree.Element
for this node which results in
>>> print get_element('info.fesa').text
7.0.0
Giving only the heading of a name is sufficient in most cases when a naming has to be given to locate or access data in the XML files.
To exclude name extension, most methods provide an optional parameter
exact_match
. If set to
True
, the path elements
must exactly match the names in the XML structure.
Obtaining Path-Strings
The class
XmlFile
provides two methods to get path-strings:
get_extended_path(path_string, baseElement=None)
:
resolves all abbreviations in the path strin, returns a path string with completed names
get_path(etree_element, baseElement=None)
:
returns the path string of a
lxml.etree.Element
in the XML tree.
As an example, presently for the instance file on scuxl0250 (presently supplying
PowerSupllyHebt _DU device
GTS7KS1) would provide
>>> print inst.get_extended_path('classes.Power.devi[GTS7K].con')
classes.PowerSupply.device-instance[name=GTS7KS1].configuration
first accessing an lxml.etree.Element and then printing it's path would provide
>>> elem = inst.get_element('classes.Power.devi[GTS7K].con')
>>> inst.get_path(elem)
'classes.PowerSupply.device-instance[GTS7KS1].configuration'
Fild Child Nodes
The xmlfesatools module provides two methods to find child nodes in the XML tree.
get_child_elements(path, baseElement=None)
will return all child elements of the XML node which is addressed by
path
, als a list of xml.etree.Element.
get_child_paths(path, baseElement=None)
will return the paths addressing all child elements of the XML node which is addressed by
path
, als a list of strings.
Reading and Writing XML-FIles
Provided with the filename as a parameter, XML files are read from disk during instantiation of the
XmlFile
objects:
inst = 1XmlFile("~myworkspace/PowerSupplyRf_DU/src/test/scuxl0037/DeviceData_PowerSupplyRf_DU.instance")
In addition to reading files from disk, FESA XML files can be fetched from a central storage, see section
web server.
To write the XML contents back to disk, the method
write_file
is provided:
write_file(self, file_name=None, backup= True)
The name of the file can be specified by parameter
file_name
. If no new name is given, the name is used from which the XML-data are read.
If the file already exists, up to three backups are created by adding ~, ~~ and ~~~ to the filename. Creation of backups can be suppressed by the optional parameter
backup
.
Structure-like Classes
Associated information should be combined in one place. For this purpose several classes are defined which provide the descriptive information by getter methods.
Class ConfigValue
The class ConfigValue holds the data of an instance file configuration parameter for a device, e.g.
<configuration><acceleratorZone>
.
def get_tag(self)
: returns the name of the configuration parameter, e.g acceleratorZone
get_path()
: returns the path of configuraiton parameter, relative to device node
e.g. configuration.acceleratorZone
, setting.dcMode
get_val()
: returns the value of a configuration parameter, e.g. 'GSI_HEBT'
get_dim()
: returns the value of the entry <dim>
, if exists
get_dim1()
: returns the value of the entry <dim1>
, if exists
get_dim2()
; returns the value of the entry <dim2>
, if exists
Class DeviceNode
The class DeviceNode holds information for a device (a nomenclature) which is listed in the XML instance file. The information can be accessed by the methods:
get_name()
: returns the nomenclature
get_class_name()
returns the name of the FESA class the device belongs to
get_device_element()
returns the xml.etree.Element
for the XML entry <device-instance>
get_event_mapping_element()
returns the xml.etree.Element
for the XML entry <events-mapping> subnode of <device-instance> entry
Class EventConfiguration
The class combines data for event-configuration elements
from the <events-mapping> event-mapping name.
The content can be accessed by the methods:
get_name()
: returns the name of the event configuration
get_type()
: returns the type of the event configuration, types are 'Timing', 'Timer', 'OnDemand', 'OnSubscription', ...
get_data()
: returns description data for the event configuration
The return data of the
get_data()
method is a list of tuples
(type, parameter)
where
type
is a string and
parameter
a dictionary of name / value pairs, as described below.
[(type, parameter), ...]
type : string
the type of the event data,
e.g. hardware-event, timer-event, on-demand-event-source-ref, on-subscription-event
parameter : dictionary {string : string, ...}
key : string
the name of the parameter,
e.g. name, period, ...
value : string
the value of the parameter,
e.g. name of the hardware-event, period of timer, ...
examples:
parameter-type | key | value
===========================+==========+======================
hardware-event | name | CMD_FG_PREP#512
---------------------------+----------+----------------------
timer | period | 1000
---------------------------+----------+----------------------
on-demand-event-source-ref | property | VoltageSetEventSource
---------------------------+----------+----------------------
on-subscription-event | context |
| device | YRT1LD51H
| property | Acquisition
Class LogicalEvent
The class holds, for a logical event, the event configurations (the mappings),
e.g. the mapping to a timing hardware-event or to a timer. The information can be access by the methods:
get_name()
: get the name of the logical event
get_class_name()
: get the name of the FESA class for which the logical event is defined
get_configuration(name)
: get the EventConfiguration object with the name name
get_configurations()
: get a list of all EventConfiguration objects for the logical event
Class Property
get:name()
Returns name of property
get_access()
Returns access ("acquisition"
, "setting"
)
get_type()
Returns type ("GSI-Reset-Property"
, GSI-Setting-Property"
, ...)
The XmlInstFile
Class
The
XmlInstFile
class provides information of FESA instance files and methods to access characteristic parts of the files. A subset of the implemented methods is listed below. For full information use the Python
help
command.
The
XmlInstFile
is a subclass of the
XmlFile
class (
see here).
get_class_name(deviceName)
get_class_names(fesaClass='')
get_deploy_unit_name()
get_deploy_unit_version()
get_fec_name()
get_fesa_version()
get_server_name()
Access Device Nodes (lxml.etree.Element
) and Device Parameters
get_device_names(fesaClass='', deviceName = '')
returns all device names, matching fesaClass
and deviceName
get_device_elements(deviceName = '', fesaClass='')
returns lxml.etree.Element
objects, matching deviceName
and fesaClass
get_device_element(deviceName = '')
returns the single lxml.etree.Element
object which matches deviceName
and fesaClass
get_device_node(deviceName)
returns a xmlfesatools.DeviceNode
object, containing some data for the device
get_device_value(deviceName, valuePath)
returns a ConfigValue
object, containing the content of a device's configuration parameter, located by path
A
ConfigValue
object represents a device's configuration parameter. It provides the value as a string and, if existing, the dimension(s). The output of the
get_device_value
method is demonstated with the parameters
<configuration><acqValue>
and
<setting><dcMode>
:
>>> print inst.get_device_value('YR10KH','con.acq')
value: {{CURRENT,-10.0,10.0,-10.0,10.0}} dim: 1
>>> print inst.get_device_value('YR10KH','set.dcMode')
value: false
Access Events-Mapping Entries
get_event_definitions()
get_event_configuration(className, eventName, eventSetting)
get_event_mapping(deviceName, evtName)
get_event_mapping_element(deviceName, eventName)
get_event_name(deviceName, eventName)
get_event_setting(deviceName, eventName)
The XmlDesignFile
Class
The
!XmlDesignClass
provides some information from FESA design files. This is presently limited to information on RT-actions and on properties.
The
XmlDesignFile
is a subclass of the
XmlFile
class (
see here).
get_class_name()
get_version()
get_rt_action_triggers()
Returns a dictionary with names of all RT-actions with lists containing the associated logical event names
get_rt_action_name(rt_action)
Returns full name which matches abbreviated RT-action name rt_action
get_all_rt_action_names(rt_action)
Returns list of al RT-actin names matching given name rt_action
get_logical_events(rt_action)
Returns list of names of all logical events associated with RT-action matching name rt_action
get_properties(access = "")
Returns dictionary, name of property with
xmlfesatools.Property
object (see
class property)
get_global_properties(access = "")
Returns global properties as dictionary, similar to get_properties
get_subset_properties(subset_name, access = "")
Returns properties for subset subset_name
, similar to get_properties
get_subsets(self)
Returns dictionary, names of subset with list of all names of properties assigned to the subset
Web-Server Files
For each FESA deploy unit which is installed in the facility, a copy of the XML instance file as well as the XML design file used to generate the FESA class is hold on a web server. These files are stored in a zip-file container.
The naming of the container is according to
<deploy-unit name>_<front-end name>.zip
, e.g.
PowerSupplyCry_DU_scuxl0142.zip
. The zip-file container contains a directory with two files, the instance file and the design file. In the given example for
scuxl0142
these are
-
PowerSupply.1.26.0.design
-
scuxl0142.instance
The Python class
xmlfesatools.FesaWebServer
represents the connection to the FESA web server.
Connection to the Web Server
For access to the web server, a class is provide which represents a connection to the web server:
ws = xmlfesatools.FesaWebServer()
Looking for Container Files
After a connection to the web server has been established, the names of the existing zip-files may be obtained.
ws.get_all_file_names()
will return a list of the names all files which are hosted on the web server.
Given parts of the names of container files, lists of matching names can be obtained.
ws.get_file_names('PowerSupply')
will return a list of container files comprizing at least all PowerSupply deploy units, while
ws.get_file_names('PowerSupply', 'kp2cu')
will return a list like ['PowerSupplyDev_DU_kp2cu01.zip' 'PowerSupplyTestDev_DU_kp2cu01.zip']
ws.get_file_name('PowerSupply', 'scu', '142')
will return a single file name, throwing an exception in case several file names match
Fetching FESA XML-Files
A web server zip container file may be obtained from the web server by
zip_file = ws.get_web_file('PowerSupply', 'scu', '0142')
The web server zip-file contains two FESA XML-files, the design file and the instance file. The
xmlfesatools
library provides tools to extract the XML files from the container. Extraction from the container will provide
xmlfesatools.XmlInstFile
and
xmlfesatools.XmlDesignFile
objects, which both inherit from
xmlfesatools.XmlFile
class.
The XML files can be extracted from the container by the
extract_web_file
method, which will return a list containing
xmlfesatools.FesaWebFile
structures:
xml_struct_list = ws.extract_web_file('PowerSupp', '0142')
The contianed FESA XML-files may be obtained directly by the methods
get_xml_file
, and especially
get_xml_instance and
get_xml_design
methods:
xml_design = ws.get_xml_design('PowerSupp', '0142')
.
will return a xmlfesatools.XmlDesignFile
object
xml_instance = ws.get_xml_instance('PowerSupp', '0142')
.
will return a xmlfesatools.XmlInstFile
object
In some cases, the zip-file contains data for several FESA classes. In such cases, the desired FESA class can be selected by providing the optional parameter
fesa_class
:
ws.get_xml_design('CaenHv', 'sddsc016', fesa_class='CaenHvSYx527')
will return the file for
CaenHvSYx527
and not for the also contained
CaenHvSYx527Channel
. The name of the FESA class can be abbreviated. In case several names match, as in the example, an exact match is preferred.