import xml.etree.ElementTree as ET
from xmlobject import XMLObject
from helpers import Struct
from pose import Pose
[docs]class XMLReader(XMLObject):
"""
A class to handle reading and parsing of XML files for the simulator and
parameters configuration files.
"""
_file = None
_root = None
def __init__(self, file_, template):
"""
Construct a new XMLReader instance
Scope:
Public
Parameters:
file_ ------> path to the file containing the XML
template ---> 'simulator' or 'parameters'
Return:
A new XMLReader instance
"""
super(XMLReader, self).__init__(file_, template)
_tree = None
try:
_tree = ET.parse(file_)
except IOError:
raise Exception('[XMLReader.__init__] Could not open ' + str(file_))
except ET.ParseError:
raise Exception('[XMLReader.__init__] Could not parse ' + str(file_))
self._root = _tree.getroot()
def _parse_parameters(self):
"""
Parse a parameters configuration file
Scope:
Private
Parameters:
None
Return:
A dictionary encapsulating the parameters.
"""
def parse_tag(rdict, tag):
"""Fill dict with data from tag"""
for attr, value in tag.items():
if attr != "id":
try:
rdict.append((attr,float(value)))
except ValueError:
rdict.append((attr,value))
for child in tag:
sub = []
id_ = child.get('id',None)
if id_ is not None:
rdict.append(((child.tag, id_),sub))
else:
rdict.append((child.tag,sub))
parse_tag(sub, child)
result = []
parse_tag(result, self._root)
return result
def _parse_color(self, color):
"""
Convert a color attribute value to int
None will yield None, '#FFACDD' will yield 0xFFACDD
Scope:
Private
Parameters:
color ----> the color to be converted
Return:
An integer value in the (AA)RRGGBB format
"""
if color is None:
return color
if color[0] == "#":
return int(color[1:],16)
color = color.lower()
if color == 'black':
return 0x000000
if color == 'red':
return 0xFF0000
if color == 'green':
return 0x00FF00
if color == 'blue':
return 0x0000FF
raise Exception('[XMLReader._parse_color] Bad color value in XML!')
def _parse_simulation(self):
"""
Parse a simulation configuration file
Scope:
Private
Parameters:
None
Return:
A list of the objects in the simulation.
"""
simulator_objects = []
# robots
for robot in self._root.findall('robot'):
robot_type = robot.get('type')
supervisor = robot.find('supervisor')
if supervisor == None:
raise Exception(
'[XMLReader._parse_simulation] No supervisor specified!')
pose = robot.find('pose')
if pose == None:
raise Exception(
'[XMLReader._parse_simulation] No pose specified!')
try:
x, y, theta = pose.get('x'), pose.get('y'), pose.get('theta')
if x == None or y == None or theta == None:
raise Exception(
'[XMLReader._parse_simulation] Invalid pose!')
robot_color = self._parse_color(robot.get('color'))
simulator_objects.append(Struct({'type':'robot',
'robot':{'type':robot_type,
'pose':Pose(float(x), float(y), float(theta)),
'color':robot_color,
'options':robot.get('options',None)},
'supervisor':{'type':supervisor.attrib['type'],
'options':supervisor.get('options',None)}}))
except ValueError:
raise Exception(
'[XMLReader._parse_simulation] Invalid robot (bad value)!')
# obstacles
for obstacle in self._root.findall('obstacle'):
pose = obstacle.find('pose')
if pose == None:
raise Exception(
'[XMLReader._parse_simulation] No pose specified!')
geometry = obstacle.find('geometry')
if geometry == None:
raise Exception(
'[XMLReader._parse_simulation] No geometry specified!')
try:
points = []
for point in geometry.findall('point'):
x, y = point.get('x'), point.get('y')
if x == None or y == None:
raise Exception(
'[XMLReader._parse_simulation] Invalid point!')
points.append((float(x), float(y)))
if len(points) < 3:
raise Exception(
'[XMLReader._parse_simulation] Too few points!')
x, y, theta = pose.get('x'), pose.get('y'), pose.get('theta')
if x == None or y == None or theta == None:
raise Exception(
'[XMLReader._parse_simulation] Invalid pose!')
color = self._parse_color(obstacle.get('color'))
simulator_objects.append(Struct({'type':'obstacle',
'polygon':{'pose':Pose(float(x),float(y),float(theta)),
'color':color,
'points':points}}))
except ValueError:
raise Exception(
'[XMLReader._parse_simulation] Invalid obstacle (bad value)!')
# background
for marker in self._root.findall('marker'):
pose = marker.find('pose')
if pose == None:
raise Exception(
'[XMLReader._parse_simulation] No pose specified!')
geometry = marker.find('geometry')
if geometry == None:
raise Exception(
'[XMLReader._parse_simulation] No geometry specified!')
try:
points = []
for point in geometry.findall('point'):
x, y = point.get('x'), point.get('y')
if x == None or y == None:
raise Exception(
'[XMLReader._parse_simulation] Invalid point!')
points.append((float(x), float(y)))
if len(points) < 3:
raise Exception(
'[XMLReader._parse_simulation] Too few points!')
x, y, theta = pose.get('x'), pose.get('y'), pose.get('theta')
if x == None or y == None or theta == None:
raise Exception(
'[XMLReader._parse_simulation] Invalid pose!')
color = self._parse_color(marker.get('color'))
simulator_objects.append(Struct({'type':'marker',
'polygon':{'pose':Pose(float(x),float(y),float(theta)),
'color':color,
'points':points}}))
except ValueError:
raise Exception(
'[XMLReader._parse_simulation] Invalid marker (bad value)!')
return simulator_objects
[docs] def read(self):
"""
Read in and parse the XML given in *file_* representing the specified *template*.
| *Parameters:*
| None
| *Return:*
| The result of reading and parsing the file. The type of return is dependent on the template, as follows:
|
| 1) **simulation**: a list of tuples representing robots, obstacles, and markers, as follows:
| ('robot', *robot_type*, *supervisor_type*, *pose*, *color*)
| ('obstacle', *pose*, [*point1*, *point2*, *point3*, ...], *color*)
| ('marker', *pose*, [*point1*, *point2*, *point3*, ...], *color*)
|
| 2) **parameters**: a dictionary representing the structure of the XML, as follows:
| { *root_element*:
| { *parameter_name*: {*attribute_name*: *attribute_value*, ... },
| ...
| (*parameter_name*, *parameter_id*): {*attribute_name*: *attribute_value*, ... },
| ...
| }
| }
"""
if self._template == "parameters":
return self._parse_parameters()
elif self._template == "simulation":
return self._parse_simulation()
else:
raise Exception(
'[XMLReader.read] Unknown template!')