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