17 Simple wrapper to add XML reflection to an xml_reflection.Object class 29 """ What to do on an error. This can be changed to raise an exception. """ 30 sys.stderr.write(message +
'\n')
38 value_type_prefix =
'' 43 Basic mechanism to prevent conflicts for string types for URDF and SDF 44 @note Does not handle nesting! 46 global value_type_prefix
47 value_type_prefix = namespace +
'.' 51 global value_type_prefix
52 value_type_prefix =
'' 56 if isinstance(key, str):
57 key = value_type_prefix + key
58 assert key
not in value_types
59 value_types[key] = value
63 """ Can wrap value types if needed """ 64 if value_type_prefix
and isinstance(cur_type, str):
66 curKey = value_type_prefix + cur_type
67 value_type = value_types.get(curKey)
70 if value_type
is None:
72 value_type = value_types.get(cur_type)
73 if value_type
is None:
80 if isinstance(cur_type, ValueType):
82 elif isinstance(cur_type, str):
83 if cur_type.startswith(
'vector'):
91 raise Exception(
"Invalid value type: {}".format(cur_type))
92 elif cur_type == list:
94 elif issubclass(cur_type, Object):
96 elif cur_type
in [str, float]:
99 raise Exception(
"Invalid type: {}".format(cur_type))
103 """ Primitive value type """ 106 return self.from_string(node.text)
110 If type has 'write_xml', this function should expect to have it's own 111 XML already created i.e., In Axis.to_sdf(self, node), 'node' would be 113 @todo Add function that makes an XML node completely independently? 115 node.text = self.to_string(value)
129 return self.
type(value)
134 return ' '.join(values)
140 return len(aValues) == len(bValues)
and all(a == b
for (a, b)
in zip(aValues, bValues))
148 if self.
count is not None:
149 assert len(values) == self.
count,
"Invalid vector length" 153 raw = list(map(str, values))
154 return ListType.to_string(self, raw)
157 raw = ListType.from_string(self, text)
159 return list(map(float, raw))
164 Simple, raw XML value. Need to bugfix putting this back into a document 174 list(map(node.append, children))
176 for (attrib_key, attrib_value)
in value.attrib.iteritems():
177 node.set(attrib_key, attrib_value)
182 Extractor that retrieves data from an element, given a 183 specified attribute, casted to value_type. 192 return self.value_type.from_string(text)
195 text = self.value_type.to_string(value)
217 for (key, value)
in typeMap.items():
222 cur_type = self.typeMap.get(node.tag)
224 raise Exception(
"Invalid {} tag: {}".format(self.
name, node.tag))
226 return value_type.from_xml(node)
230 name = self.nameMap.get(cur_type)
232 raise Exception(
"Invalid {} type: {}".format(self.
name, cur_type))
242 assert len(typeOrder) > 0
249 return value_type.from_xml(node)
250 except Exception
as e:
251 error_set.append((value_type, e))
253 out =
"Could not perform duck-typed parsing." 254 for (value_type, e)
in error_set:
255 out +=
"\nValue Type: {}\nException: {}\n".format(value_type, e)
263 """ Mirroring Gazebo's SDF api 265 @param xml_var: Xml name 266 @todo If the value_type is an object with a tag defined in it's 267 reflection, allow it to act as the default tag name? 268 @param var: Python class variable name. By default it's the same as the 272 def __init__(self, xml_var, value_type, required=True, default=None,
283 assert default
is None,
"Default does not make sense for a required field" 289 raise Exception(
"Required {} not set in XML: {}".format(self.
type, self.
xml_var))
290 elif not skip_default:
295 def __init__(self, xml_var, value_type, required=True, default=None,
297 Param.__init__(self, xml_var, value_type, required, default, var)
301 """ Node is the parent node in this case """ 303 setattr(obj, self.
var, self.value_type.from_string(value))
306 value = getattr(obj, self.
var)
310 raise Exception(
"Required attribute not set in object: {}".format(self.
var))
311 elif not skip_default:
314 if value
is not None:
315 node.set(self.
xml_var, self.value_type.to_string(value))
323 def __init__(self, xml_var, value_type, required=True, default=None,
324 var=
None, is_raw=
False):
325 Param.__init__(self, xml_var, value_type, required, default, var)
330 value = self.value_type.from_xml(node)
331 setattr(obj, self.
var, value)
334 value = getattr(obj, self.
xml_var)
337 raise Exception(
"Required element not defined in object: {}".format(self.
var))
338 elif not skip_default:
340 if value
is not None:
348 self.value_type.write_xml(node, value)
352 def __init__(self, xml_var, value_type, var=None, is_raw=False):
355 Element.__init__(self, xml_var, value_type, required=
False, var=var,
360 value = self.value_type.from_xml(node)
361 obj.add_aggregate(self.
xml_var, value)
368 """ Small container for keeping track of what's been consumed """ 376 def __init__(self, params=[], parent_cls=None, tag=None):
377 """ Construct a XML reflection thing 378 @param parent_cls: Parent class, to use it's reflection as well. 379 @param tag: Only necessary if you intend to use Object.write_xml_doc() 380 This does not override the name supplied in the reflection 383 if parent_cls
is not None:
393 if isinstance(param, Element):
394 elements.append(param)
396 attributes.append(param)
404 for attribute
in attributes:
406 self.
paramMap[attribute.xml_var] = attribute
407 self.vars.append(attribute.var)
408 if attribute.required:
409 self.required_attribute_names.append(attribute.xml_var)
417 for element
in elements:
419 self.
paramMap[element.xml_var] = element
420 self.vars.append(element.var)
422 self.required_element_names.append(element.xml_var)
423 if element.is_aggregate:
424 self.aggregates.append(element)
426 self.scalars.append(element)
427 self.scalarNames.append(element.xml_var)
436 self.parent.set_from_xml(obj, node, info)
439 unset_attributes = list(self.attribute_map.keys())
442 for xml_var
in copy.copy(info.attributes):
443 attribute = self.attribute_map.get(xml_var)
444 if attribute
is not None:
445 value = node.attrib[xml_var]
446 attribute.set_from_string(obj, value)
447 unset_attributes.remove(xml_var)
448 info.attributes.remove(xml_var)
451 for child
in copy.copy(info.children):
453 element = self.element_map.get(tag)
454 if element
is not None:
455 if element.is_aggregate:
456 element.add_from_xml(obj, child)
458 if tag
in unset_scalars:
459 element.set_from_xml(obj, child)
460 unset_scalars.remove(tag)
462 on_error(
"Scalar element defined multiple times: {}".format(tag))
463 info.children.remove(child)
465 for attribute
in map(self.attribute_map.get, unset_attributes):
466 attribute.set_default(obj)
468 for element
in map(self.element_map.get, unset_scalars):
469 element.set_default(obj)
472 for xml_var
in info.attributes:
473 on_error(
'Unknown attribute: {}'.format(xml_var))
474 for node
in info.children:
475 on_error(
'Unknown tag: {}'.format(node.tag))
479 self.parent.add_to_xml(obj, node)
481 attribute.add_to_xml(obj, node)
483 element.add_to_xml(obj, node)
486 obj.add_aggregates_to_xml(node)
490 """ Raw python object for yaml / xml representation """ 494 return self.XML_REFL.vars
500 """ If anything needs to be converted prior to dumping to xml 501 i.e., getting the names of objects and such """ 505 """ Adds contents directly to XML node """ 508 self.XML_REFL.add_to_xml(self, node)
511 """ Creates an overarching tag and adds its contents to the node """ 512 tag = self.XML_REFL.tag
513 assert tag
is not None,
"Must define 'tag' in reflection to use this function" 514 doc = etree.Element(tag)
525 self.XML_REFL.set_from_xml(self, node)
532 return cur_type.from_xml(node)
536 node = etree.fromstring(xml_string)
541 xml_string = open(file_path,
'r').read() 548 var = self.XML_REFL.paramMap[xml_var].var
549 values = getattr(self, var)
550 assert isinstance(values, list)
554 """ Must be called in constructor! """ 560 """ NOTE: One must keep careful track of aggregate types for this system. 561 Can use 'lump_aggregates()' before writing if you don't care. """ 563 self.aggregate_order.append(obj)
569 element = self.XML_REFL.element_map[typeName]
570 element.add_scalar_to_xml(node, value)
573 self.aggregate_order.remove(obj)
579 """ Put all aggregate types together, just because """ 581 for param
in self.XML_REFL.aggregates:
585 """ Compatibility """ 588 node = etree.fromstring(xml_string)
def from_string(self, text)
def set_default(self, obj)
def set_from_string(self, obj, value)
def start_namespace(namespace)
def from_xml_file(cls, file_path)
def set_default(self, obj)
def get_aggregate_list(self, xml_var)
def __init__(self, xml_var, value_type, required=True, default=None, var=None)
def add_to_xml(self, obj, parent)
def __init__(self, params=[], parent_cls=None, tag=None)
def set_from_xml(self, obj, node, info=None)
def __init__(self, cur_type)
def __init__(self, xml_var, value_type, var=None, is_raw=False)
def __init__(self, xml_var, value_type, required=True, default=None, var=None)
def write_xml(self, node, value)
def write_xml(self, node)
def add_aggregate(self, xml_var, obj)
def write_xml(self, node, value)
def lump_aggregates(self)
def equals(self, aValues, bValues)
def from_string(self, value)
def from_string(self, text)
def reflect(cls, args, kwargs)
def add_to_xml(self, obj, node)
def add_scalar_to_xml(self, parent, value)
def write_xml(self, node, obj)
def write_xml(self, node, obj)
def set_from_xml(self, obj, node)
def from_xml_string(cls, xml_string)
def to_string(self, values)
def xml_string(rootXml, addHeader=True)
def to_string(self, values)
def add_aggregates_to_xml(self, node)
def __init__(self, attribute, value_type)
def __init__(self, cur_type)
def __init__(self, xml_var, value_type, required=True, default=None, var=None, is_raw=False)
def remove_aggregate(self, obj)
def write_xml(self, node, obj)
def add_from_xml(self, obj, node)
def to_string(self, value)
def __init__(self, name, typeMap)
def add_to_xml(self, obj, node)
def to_xml_string(self, addHeader=True)
def parse(self, xml_string)
def __init__(self, name, typeOrder)
def write_xml(self, node, value)
def __init__(self, count=None)