1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 """
36 Roslaunch XML file parser.
37 """
38
39 from __future__ import print_function
40
41 import itertools
42 import sys
43 import traceback
44 import logging
45
46 from xml.dom.minidom import parse, parseString
47 from xml.dom import Node as DomNode
48
49 from rosgraph.names import make_global_ns, ns_join, is_private, is_legal_name, get_ros_namespace
50 from rospkg import ResourceNotFound
51
52 from .core import Param, Node, Test, Machine, RLException
53 from . import loader
54 from . import substitution_args
55
56
57 SubstitutionException = substitution_args.SubstitutionException
58 ArgException = substitution_args.ArgException
59
60 NS='ns'
61 CLEAR_PARAMS='clear_params'
62
63 -def _get_text(tag):
64 buff = ''
65 for t in tag.childNodes:
66 if t.nodeType in [t.TEXT_NODE, t.CDATA_SECTION_NODE]:
67 buff += t.data
68 return buff
69
71 """
72 @return True: if tag should be processed according to its if/unless attributes
73 """
74 if_val, unless_val = obj.opt_attrs(tag, context, ['if', 'unless'])
75 if if_val is not None and unless_val is not None:
76 raise XmlParseException("cannot set both 'if' and 'unless' on the same tag")
77 if if_val is not None:
78 if_val = loader.convert_value(if_val, 'bool')
79 if if_val:
80 return True
81 elif unless_val is not None:
82 unless_val = loader.convert_value(unless_val, 'bool')
83 if not unless_val:
84 return True
85 else:
86 return True
87 return False
88
90 """
91 Decorator for evaluating whether or not tag function should run based on if/unless attributes
92 """
93 def call(*args, **kwds):
94
95 if ifunless_test(args[0], args[1], args[2]):
96 return f(*args, **kwds)
97 return call
98
104 """Error with the XML syntax (e.g. invalid attribute/value combinations)"""
105 pass
106
108 """
109 Validate boolean xml attribute.
110 @param v: parameter value or None if no value provided
111 @type v: any
112 @param default: default value
113 @type default: bool
114 @param label: parameter name/label
115 @type label: str
116 @return: boolean value for attribute
117 @rtype: bool
118 @raise XmlParseException: if v is not in correct range or is empty.
119 """
120 if v is None:
121 return default
122 if v.lower() == 'true':
123 return True
124 elif v.lower() == 'false':
125 return False
126 elif not v:
127 raise XmlParseException("bool value for %s must be non-empty"%(label))
128 else:
129 raise XmlParseException("invalid bool value for %s: %s"%(label, v))
130
132 """
133 Validate float xml attribute.
134 @param v: parameter value or None if no value provided
135 @type v: any
136 @param default: default value
137 @type default: float
138 @param label: parameter name/label
139 @type label: str
140 @return: float value for attribute
141 @rtype: float
142 @raise XmlParseException: if v is not in correct range or is empty.
143 """
144 if v is None:
145 return default
146 if not v:
147 raise XmlParseException("bool value for %s must be non-empty"%(label))
148 try:
149 x = float(v)
150 except ValueError:
151 raise XmlParseException("invalid float value for %s: %s"%(label, v))
152 return x
153
154
155
156 _is_default = {'true': True, 'false': False, 'never': False }
157
158 _assignable = {'true': True, 'false': True, 'never': False }
159
160
161
162
163 -class XmlLoader(loader.Loader):
164 """
165 Parser for roslaunch XML format. Loads parsed representation into ROSConfig model.
166 """
167
168 - def __init__(self, resolve_anon=True, args_only=False):
169 """
170 @param resolve_anon: If True (default), will resolve $(anon foo). If
171 false, will leave these args as-is.
172 @type resolve_anon: bool
173 @param args_only: if True, will only load arg tags (e.g. autocompletion purposes)
174 @type args_only: bool
175 """
176
177 self.root_context = None
178 self.resolve_anon = resolve_anon
179 self.args_only = args_only
180
182 """
183 Wrapper around substitution_args.resolve_args to set common parameters
184 """
185
186 if args and '$' in args:
187
188 context.resolve_dict['filename'] = context.filename
189 return substitution_args.resolve_args(args, context=context.resolve_dict, resolve_anon=self.resolve_anon)
190 else:
191 return args
192
194 """
195 Helper routine for fetching and resolving optional tag attributes
196 @param tag DOM tag
197 @param context LoaderContext
198 @param attrs (str): list of attributes to resolve
199 """
200 def tag_value(tag, a):
201 if tag.hasAttribute(a):
202
203
204
205 return tag.getAttribute(a)
206 else:
207 return None
208 return [self.resolve_args(tag_value(tag,a), context) for a in attrs]
209
211 """
212 Helper routine for fetching and resolving required tag attributes
213 @param tag: DOM tag
214 @param attrs: list of attributes to resolve
215 @type attrs: (str)
216 @raise KeyError: if required attribute is missing
217 """
218 return [self.resolve_args(tag.attributes[a].value, context) for a in attrs]
219
221 tag_attrs = tag.attributes.keys()
222 for t_a in tag_attrs:
223 if not t_a in attrs and not t_a in ['if', 'unless']:
224 ros_config.add_config_error("[%s] unknown <%s> attribute '%s'"%(context.filename, tag.tagName, t_a))
225
226
227
228
229 ROSPARAM_OPT_ATTRS = ('command', 'ns', 'file', 'param', 'subst_value')
230 @ifunless
231 - def _rosparam_tag(self, tag, context, ros_config, verbose=True):
232 try:
233 self._check_attrs(tag, context, ros_config, XmlLoader.ROSPARAM_OPT_ATTRS)
234 cmd, ns, file, param, subst_value = self.opt_attrs(tag, context, (XmlLoader.ROSPARAM_OPT_ATTRS))
235 subst_value = _bool_attr(subst_value, False, 'subst_value')
236
237 param = ns_join(ns or '', param or '')
238
239
240 cmd = cmd or 'load'
241 value = _get_text(tag)
242 subst_function = None
243 if subst_value:
244 subst_function = lambda x: self.resolve_args(x, context)
245 self.load_rosparam(context, ros_config, cmd, param, file, value, verbose=verbose, subst_function=subst_function)
246
247 except ValueError as e:
248 raise loader.LoadException("error loading <rosparam> tag: \n\t"+str(e)+"\nXML is %s"%tag.toxml())
249
250 PARAM_ATTRS = ('name', 'value', 'type', 'value', 'textfile', 'binfile', 'command')
251 @ifunless
252 - def _param_tag(self, tag, context, ros_config, force_local=False, verbose=True):
253 """
254 @param force_local: if True, param must be added to context instead of ros_config
255 @type force_local: bool
256 """
257 try:
258 self._check_attrs(tag, context, ros_config, XmlLoader.PARAM_ATTRS)
259
260
261 ptype = (tag.getAttribute('type') or 'auto').lower().strip()
262
263 vals = self.opt_attrs(tag, context, ('value', 'textfile', 'binfile', 'command'))
264 if len([v for v in vals if v is not None]) != 1:
265 raise XmlParseException(
266 "<param> tag must have one and only one of value/textfile/binfile.")
267
268
269
270 name = self.resolve_args(tag.attributes['name'].value.strip(), context)
271 value = self.param_value(verbose, name, ptype, *vals)
272
273 if is_private(name) or force_local:
274 p = Param(name, value)
275 context.add_param(p)
276 else:
277 p = Param(ns_join(context.ns, name), value)
278 ros_config.add_param(Param(ns_join(context.ns, name), value), filename=context.filename, verbose=verbose)
279 return p
280
281 except KeyError as e:
282 raise XmlParseException(
283 "<param> tag is missing required attribute: %s. \n\nParam xml is %s"%(e, tag.toxml()))
284 except ValueError as e:
285 raise XmlParseException(
286 "Invalid <param> tag: %s. \n\nParam xml is %s"%(e, tag.toxml()))
287
288 ARG_ATTRS = ('name', 'value', 'default', 'doc')
289 @ifunless
290 - def _arg_tag(self, tag, context, ros_config, verbose=True):
291 """
292 Process an <arg> tag.
293 """
294 try:
295 self._check_attrs(tag, context, ros_config, XmlLoader.ARG_ATTRS)
296 (name,) = self.reqd_attrs(tag, context, ('name',))
297 value, default, doc = self.opt_attrs(tag, context, ('value', 'default', 'doc'))
298
299 if value is not None and default is not None:
300 raise XmlParseException(
301 "<arg> tag must have one and only one of value/default.")
302
303 context.add_arg(name, value=value, default=default, doc=doc)
304
305 except substitution_args.ArgException as e:
306 raise XmlParseException(
307 "arg '%s' is not defined. \n\nArg xml is %s"%(e, tag.toxml()))
308 except ResourceNotFound as e:
309 raise ResourceNotFound(
310 "The following package was not found in {}: {}".format(tag.toxml(), e))
311 except Exception as e:
312 raise XmlParseException(
313 "Invalid <arg> tag: %s. \n\nArg xml is %s"%(e, tag.toxml()))
314
342
343 NODE_ATTRS = ['pkg', 'type', 'machine', 'name', 'args', 'output', \
344 'respawn', 'respawn_delay', 'cwd', NS, CLEAR_PARAMS, \
345 'launch-prefix', 'required']
346 TEST_ATTRS = NODE_ATTRS + ['test-name','time-limit', 'retry']
347
348 @ifunless
349 - def _node_tag(self, tag, context, ros_config, default_machine, is_test=False, verbose=True):
350 """
351 Process XML <node> or <test> tag
352 @param tag: DOM node
353 @type tag: Node
354 @param context: namespace context
355 @type context: L{LoaderContext}
356 @param params: ROS parameter list
357 @type params: [L{Param}]
358 @param clear_params: list of ROS parameter names to clear before setting parameters
359 @type clear_params: [str]
360 @param default_machine: default machine to assign to node
361 @type default_machine: str
362 @param is_test: if set, will load as L{Test} object instead of L{Node} object
363 @type is_test: bool
364 """
365 try:
366 if is_test:
367 self._check_attrs(tag, context, ros_config, XmlLoader.TEST_ATTRS)
368 (name,) = self.opt_attrs(tag, context, ('name',))
369 test_name, time_limit, retry = self._test_attrs(tag, context)
370 if not name:
371 name = test_name
372 else:
373 self._check_attrs(tag, context, ros_config, XmlLoader.NODE_ATTRS)
374 (name,) = self.reqd_attrs(tag, context, ('name',))
375
376 if not is_legal_name(name):
377 ros_config.add_config_error("WARN: illegal <node> name '%s'.\nhttp://ros.org/wiki/Names\nThis will likely cause problems with other ROS tools.\nNode xml is %s"%(name, tag.toxml()))
378
379 child_ns = self._ns_clear_params_attr('node', tag, context, ros_config, node_name=name)
380 param_ns = child_ns.child(name)
381 param_ns.params = []
382
383
384 pkg, node_type = self.reqd_attrs(tag, context, ('pkg', 'type'))
385
386
387 machine, args, output, respawn, respawn_delay, cwd, launch_prefix, \
388 required = self.opt_attrs(tag, context, ('machine', 'args',
389 'output', 'respawn', 'respawn_delay', 'cwd',
390 'launch-prefix', 'required'))
391 if not machine and default_machine:
392 machine = default_machine.name
393
394 required, respawn = [_bool_attr(*rr) for rr in ((required, False, 'required'),\
395 (respawn, False, 'respawn'))]
396 respawn_delay = _float_attr(respawn_delay, 0.0, 'respawn_delay')
397
398
399
400 remap_context = context.child('')
401
402
403
404 env_context = context.child('')
405
406
407
408 for t in [c for c in tag.childNodes if c.nodeType == DomNode.ELEMENT_NODE]:
409 tag_name = t.tagName.lower()
410 if tag_name == 'remap':
411 r = self._remap_tag(t, context, ros_config)
412 if r is not None:
413 remap_context.add_remap(r)
414 elif tag_name == 'param':
415 self._param_tag(t, param_ns, ros_config, force_local=True, verbose=verbose)
416 elif tag_name == 'rosparam':
417 self._rosparam_tag(t, param_ns, ros_config, verbose=verbose)
418 elif tag_name == 'env':
419 self._env_tag(t, env_context, ros_config)
420 else:
421 ros_config.add_config_error("WARN: unrecognized '%s' child tag in the parent tag element: %s"%(t.tagName, tag.toxml()))
422
423
424
425 for p in itertools.chain(context.params, param_ns.params):
426 pkey = p.key
427 if is_private(pkey):
428
429 pkey = pkey[1:]
430 pkey = param_ns.ns + pkey
431 ros_config.add_param(Param(pkey, p.value), verbose=verbose)
432
433 if not is_test:
434 return Node(pkg, node_type, name=name, namespace=child_ns.ns, machine_name=machine,
435 args=args, respawn=respawn,
436 respawn_delay=respawn_delay,
437 remap_args=remap_context.remap_args(), env_args=env_context.env_args,
438 output=output, cwd=cwd, launch_prefix=launch_prefix,
439 required=required, filename=context.filename)
440 else:
441 return Test(test_name, pkg, node_type, name=name, namespace=child_ns.ns,
442 machine_name=machine, args=args,
443 remap_args=remap_context.remap_args(), env_args=env_context.env_args,
444 time_limit=time_limit, cwd=cwd, launch_prefix=launch_prefix,
445 retry=retry, filename=context.filename)
446 except KeyError as e:
447 raise XmlParseException(
448 "<%s> tag is missing required attribute: %s. Node xml is %s"%(tag.tagName, e, tag.toxml()))
449 except XmlParseException as e:
450 raise XmlParseException(
451 "Invalid <node> tag: %s. \n\nNode xml is %s"%(e, tag.toxml()))
452 except ValueError as e:
453 raise XmlParseException(
454 "Invalid <node> tag: %s. \n\nNode xml is %s"%(e, tag.toxml()))
455
456 MACHINE_ATTRS = ('name', 'address', 'env-loader',
457 'ssh-port', 'user', 'password', 'default', 'timeout')
458 @ifunless
459 - def _machine_tag(self, tag, context, ros_config, verbose=True):
460 try:
461
462 context = context.child(None)
463
464
465 attrs = self.opt_attrs(tag, context,
466 ('ros-root', 'ros-package-path', 'ros-ip', 'ros-hostname'))
467 if any(attrs):
468 raise XmlParseException("<machine>: ros-* attributes are not supported since ROS Fuerte.\nPlease use env-loader instead")
469
470 self._check_attrs(tag, context, ros_config, XmlLoader.MACHINE_ATTRS)
471
472 name, address = self.reqd_attrs(tag, context, ('name', 'address'))
473
474
475 attrs = self.opt_attrs(tag, context,
476 ('env-loader',
477 'ssh-port', 'user', 'password', 'default', 'timeout'))
478 env_loader, ssh_port, user, password, default, timeout = attrs
479
480 ssh_port = int(ssh_port or '22')
481
482
483 default = (default or 'false').lower()
484 try:
485 assignable = _assignable[default]
486 is_default = _is_default[default]
487 except KeyError as e:
488 raise XmlParseException("Invalid value for 'attribute': %s"%default)
489
490
491 for t in [c for c in tag.childNodes if c.nodeType == DomNode.ELEMENT_NODE]:
492 if t.tagName == 'env':
493 raise XmlParseException("<machine>: <env> tag is not supported since ROS Fuerte.\nPlease use env-loader instead")
494 else:
495 ros_config.add_config_error("unrecognized '%s' tag in <%s> tag"%(t.tagName, tag.tagName))
496
497 if timeout:
498 try:
499 timeout = float(timeout)
500 except ValueError:
501 raise XmlParseException("'timeout' be a number: [%s]"%timeout)
502 elif timeout == '':
503 raise XmlParseException("'timeout' cannot be empty")
504 if timeout is not None and timeout <= 0.:
505 raise XmlParseException("'timeout' be a positive number: [%s]"%timeout)
506
507 m = Machine(name, address, env_loader=env_loader,
508 ssh_port=ssh_port, user=user, password=password,
509 assignable=assignable, env_args=context.env_args, timeout=timeout)
510 return (m, is_default)
511 except KeyError as e:
512 raise XmlParseException("<machine> tag is missing required attribute: %s"%e)
513 except SubstitutionException as e:
514 raise XmlParseException(
515 "%s. \n\nMachine xml is %s"%(e, tag.toxml()))
516 except RLException as e:
517 raise XmlParseException(
518 "%s. \n\nMachine xml is %s"%(e, tag.toxml()))
519
520 REMAP_ATTRS = ('from', 'to')
521 @ifunless
528
529 ENV_ATTRS = ('name', 'value')
530 @ifunless
531 - def _env_tag(self, tag, context, ros_config):
539
540 - def _ns_clear_params_attr(self, tag_name, tag, context, ros_config, node_name=None, include_filename=None):
541 """
542 Common processing routine for xml tags with NS and CLEAR_PARAMS attributes
543
544 @param tag: DOM Node
545 @type tag: Node
546 @param context: current namespace context
547 @type context: LoaderContext
548 @param clear_params: list of params to clear
549 @type clear_params: [str]
550 @param node_name: name of node (for use when tag_name == 'node')
551 @type node_name: str
552 @param include_filename: <include> filename if this is an <include> tag. If specified, context will use include rules.
553 @type include_filename: str
554 @return: loader context
555 @rtype: L{LoaderContext}
556 """
557 if tag.hasAttribute(NS):
558 ns = self.resolve_args(tag.getAttribute(NS), context)
559 if not ns:
560 raise XmlParseException("<%s> tag has an empty '%s' attribute"%(tag_name, NS))
561 else:
562 ns = None
563 if include_filename is not None:
564 child_ns = context.include_child(ns, include_filename)
565 else:
566 child_ns = context.child(ns)
567 clear_p = self.resolve_args(tag.getAttribute(CLEAR_PARAMS), context)
568 if clear_p:
569 clear_p = _bool_attr(clear_p, False, 'clear_params')
570 if clear_p:
571 if tag_name == 'node':
572 if not node_name:
573 raise XmlParseException("<%s> tag must have a 'name' attribute to use '%s' attribute"%(tag_name, CLEAR_PARAMS))
574
575 ros_config.add_clear_param(make_global_ns(ns_join(child_ns.ns, node_name)))
576 else:
577 if not ns:
578 raise XmlParseException("'ns' attribute must be set in order to use 'clear_params'")
579 ros_config.add_clear_param(child_ns.ns)
580 return child_ns
581
582 @ifunless
583 - def _launch_tag(self, tag, ros_config, filename=None):
584
585 deprecated = tag.getAttribute('deprecated')
586 if deprecated:
587 if filename:
588 ros_config.add_config_error("[%s] DEPRECATED: %s"%(filename, deprecated))
589 else:
590 ros_config.add_config_error("Deprecation Warning: "+deprecated)
591
592 INCLUDE_ATTRS = ('file', NS, CLEAR_PARAMS, 'pass_all_args')
593 @ifunless
594 - def _include_tag(self, tag, context, ros_config, default_machine, is_core, verbose):
595 self._check_attrs(tag, context, ros_config, XmlLoader.INCLUDE_ATTRS)
596 inc_filename = self.resolve_args(tag.attributes['file'].value, context)
597
598 if tag.hasAttribute('pass_all_args'):
599 pass_all_args = self.resolve_args(tag.attributes['pass_all_args'].value, context)
600 pass_all_args = _bool_attr(pass_all_args, False, 'pass_all_args')
601 else:
602 pass_all_args = False
603
604 child_ns = self._ns_clear_params_attr(tag.tagName, tag, context, ros_config, include_filename=inc_filename)
605
606
607
608 if pass_all_args:
609 if 'arg' in context.resolve_dict:
610 for name, value in context.resolve_dict['arg'].items():
611 child_ns.add_arg(name, value=value)
612
613
614 child_ns.pass_all_args = True
615
616 for t in [c for c in tag.childNodes if c.nodeType == DomNode.ELEMENT_NODE]:
617 tag_name = t.tagName.lower()
618 if tag_name == 'env':
619 self._env_tag(t, child_ns, ros_config)
620 elif tag_name == 'arg':
621 self._arg_tag(t, child_ns, ros_config, verbose=verbose)
622 else:
623 print("WARN: unrecognized '%s' tag in <%s> tag"%(t.tagName, tag.tagName), file=sys.stderr)
624
625
626 loader.process_include_args(child_ns)
627
628 try:
629 launch = self._parse_launch(inc_filename, verbose=verbose)
630 ros_config.add_roslaunch_file(inc_filename)
631 self._launch_tag(launch, ros_config, filename=inc_filename)
632 default_machine = \
633 self._recurse_load(ros_config, launch.childNodes, child_ns, \
634 default_machine, is_core, verbose)
635
636 if not pass_all_args:
637
638 loader.post_process_include_args(child_ns)
639
640 except ArgException as e:
641 if not self.ignore_unset_args:
642 raise XmlParseException("included file [%s] requires the '%s' arg to be set"%(inc_filename, str(e)))
643 except XmlParseException as e:
644 raise XmlParseException("while processing %s:\n%s"%(inc_filename, str(e)))
645 if verbose:
646 print("... done importing include file [%s]"%inc_filename)
647 return default_machine
648
649 GROUP_ATTRS = (NS, CLEAR_PARAMS)
650 - def _recurse_load(self, ros_config, tags, context, default_machine, is_core, verbose):
651 """
652 @return: new default machine for current context
653 @rtype: L{Machine}
654 """
655 for tag in [t for t in tags if t.nodeType == DomNode.ELEMENT_NODE]:
656 name = tag.tagName
657 if name == 'arg':
658 self._arg_tag(tag, context, ros_config, verbose=verbose)
659 elif self.args_only:
660
661 continue
662 elif name == 'group':
663 if ifunless_test(self, tag, context):
664 self._check_attrs(tag, context, ros_config, XmlLoader.GROUP_ATTRS)
665 child_ns = self._ns_clear_params_attr(name, tag, context, ros_config)
666 child_ns.params = list(child_ns.params)
667 default_machine = \
668 self._recurse_load(ros_config, tag.childNodes, child_ns, \
669 default_machine, is_core, verbose)
670 elif name == 'node':
671 n = self._node_tag(tag, context, ros_config, default_machine, verbose=verbose)
672 if n is not None:
673 ros_config.add_node(n, core=is_core, verbose=verbose)
674 elif name == 'test':
675 t = self._node_tag(tag, context, ros_config, default_machine, is_test=True, verbose=verbose)
676 if t is not None:
677 ros_config.add_test(t, verbose=verbose)
678 elif name == 'param':
679 self._param_tag(tag, context, ros_config, verbose=verbose)
680 elif name == 'remap':
681 try:
682 r = self._remap_tag(tag, context, ros_config)
683 if r is not None:
684 context.add_remap(r)
685 except RLException as e:
686 raise XmlParseException("Invalid <remap> tag: %s.\nXML is %s"%(str(e), tag.toxml()))
687 elif name == 'machine':
688 val = self._machine_tag(tag, context, ros_config, verbose=verbose)
689 if val is not None:
690 (m, is_default) = val
691 if is_default:
692 default_machine = m
693 ros_config.add_machine(m, verbose=verbose)
694 elif name == 'rosparam':
695 self._rosparam_tag(tag, context, ros_config, verbose=verbose)
696 elif name == 'master':
697 pass
698 elif name == 'include':
699 val = self._include_tag(tag, context, ros_config, default_machine, is_core, verbose)
700 if val is not None:
701 default_machine = val
702 elif name == 'env':
703 self._env_tag(tag, context, ros_config)
704 else:
705 ros_config.add_config_error("unrecognized tag "+tag.tagName)
706 return default_machine
707
708 - def _load_launch(self, launch, ros_config, is_core=False, filename=None, argv=None, verbose=True):
709 """
710 subroutine of launch for loading XML DOM into config. Load_launch assumes that it is
711 creating the root XmlContext, and is thus affected by command-line arguments.
712 @param launch: DOM node of the root <launch> tag in the file
713 @type launch: L{Node}
714 @param ros_config: launch configuration to load XML file into
715 @type ros_config: L{ROSLaunchConfig}
716 @param is_core: (optional) if True, load file using ROS core rules. Default False.
717 @type is_core: bool
718 @param filename: (optional) name of file being loaded
719 @type filename: str
720 @param verbose: (optional) print verbose output. Default False.
721 @type verbose: bool
722 @param argv: (optional) command-line args. Default sys.argv.
723 """
724 if argv is None:
725 argv = sys.argv
726
727 self._launch_tag(launch, ros_config, filename)
728 self.root_context = loader.LoaderContext(get_ros_namespace(argv=argv), filename)
729 loader.load_sysargs_into_context(self.root_context, argv)
730
731 if len(launch.getElementsByTagName('master')) > 0:
732 print("WARNING: ignoring defunct <master /> tag", file=sys.stderr)
733 self._recurse_load(ros_config, launch.childNodes, self.root_context, None, is_core, verbose)
734
736 try:
737 if verbose:
738 print("... loading XML file [%s]"%filename)
739 root = parse(filename).getElementsByTagName('launch')
740 except Exception as e:
741 raise XmlParseException("Invalid roslaunch XML syntax: %s"%e)
742 if len(root) != 1:
743 raise XmlParseException("Invalid roslaunch XML syntax: no root <launch> tag")
744 return root[0]
745
746 - def load(self, filename, ros_config, core=False, argv=None, verbose=True):
747 """
748 load XML file into launch configuration
749 @param filename: XML config file to load
750 @type filename: str
751 @param ros_config: launch configuration to load XML file into
752 @type ros_config: L{ROSLaunchConfig}
753 @param core: if True, load file using ROS core rules
754 @type core: bool
755 @param argv: override command-line arguments (mainly for arg testing)
756 @type argv: [str]
757 """
758 try:
759 launch = self._parse_launch(filename, verbose)
760 ros_config.add_roslaunch_file(filename)
761 self._load_launch(launch, ros_config, is_core=core, filename=filename, argv=argv, verbose=verbose)
762 except ArgException as e:
763 if not self.ignore_unset_args:
764 raise XmlParseException("[%s] requires the '%s' arg to be set"%(filename, str(e)))
765 except SubstitutionException as e:
766 raise XmlParseException(str(e))
767
768 - def load_string(self, xml_text, ros_config, core=False, verbose=True):
769 """
770 Load XML text into launch configuration
771 @param xml_text: XML configuration
772 @type xml_text: str
773 @param ros_config: launch configuration to load XML file into
774 @type ros_config: L{ROSLaunchConfig}
775 @param core: if True, load file using ROS core rules
776 @type core: bool
777 """
778 try:
779 if verbose:
780 print("... loading XML")
781 try:
782 if hasattr(xml_text,'encode') and isinstance(xml_text, unicode):
783
784
785
786 xml_text = xml_text.encode('utf-8')
787 except NameError:
788 pass
789 root = parseString(xml_text).getElementsByTagName('launch')
790 except Exception as e:
791 logging.getLogger('roslaunch').error("Invalid roslaunch XML syntax:\nstring[%s]\ntraceback[%s]"%(xml_text, traceback.format_exc()))
792 raise XmlParseException("Invalid roslaunch XML syntax: %s"%e)
793
794 if len(root) != 1:
795 raise XmlParseException("Invalid roslaunch XML syntax: no root <launch> tag")
796 self._load_launch(root[0], ros_config, core, filename='string', verbose=verbose)
797