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