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