33 from __future__
import print_function
43 from xml.dom.minidom
import parse
45 import substitution_args
46 from names
import load_mappings
54 substitution_args_context = {}
62 return hasattr(x,
'__int__')
75 writer.write(indent +
"<" + self.tagName)
77 attrs = self._get_attributes()
78 a_names = list(attrs.keys())
81 for a_name
in a_names:
82 writer.write(
" %s=\"" % a_name)
83 xml.dom.minidom._write_data(writer, attrs[a_name].value)
86 if len(self.childNodes) == 1 \
87 and self.childNodes[0].nodeType == xml.dom.minidom.Node.TEXT_NODE:
89 self.childNodes[0].writexml(writer,
"",
"",
"")
90 writer.write(
"</%s>%s" % (self.tagName, newl))
92 writer.write(
">%s" % (newl))
93 for node
in self.childNodes:
95 if node.nodeType == xml.dom.minidom.Node.TEXT_NODE
and \
96 not node.data.strip():
98 node.writexml(writer, indent + addindent, addindent, newl)
99 writer.write(
"%s</%s>%s" % (indent, self.tagName, newl))
101 writer.write(
"/>%s" % (newl))
103 xml.dom.minidom.Element.writexml = fixed_writexml
107 def __init__(self, parent=None):
111 def __getitem__(self, key):
112 if key
in self.table:
113 return self.table[key]
115 return self.parent[key]
119 def __setitem__(self, key, value):
120 self.table[key] = value
122 def __contains__(self, key):
124 key
in self.table
or \
125 (self.parent
and key
in self.parent)
129 def __init__(self, **res):
133 for k, v
in res.items():
134 self.__setattr__(k,
len(self.res))
148 for i
in range(
len(self.res)):
149 m = re.match(self.res[i], self.str)
151 self.top = (i, m.group(0))
152 self.str = self.str[m.end():]
160 if c.nodeType == xml.dom.Node.ELEMENT_NODE:
169 if c.nodeType == xml.dom.Node.ELEMENT_NODE:
180 while elt
and elt.nodeType == xml.dom.Node.ELEMENT_NODE:
191 return node.firstChild
194 return node.nextSibling
195 node = node.parentNode
208 deprecated_include_msg =
"""DEPRECATED IN HYDRO: 209 The <include> tag should be prepended with 'xacro' if that is the intended use 210 of it, such as <xacro:include ...>. Use the following script to fix incorrect 212 sed -i 's/<include/<xacro:include/g' `find . -iname *.xacro`""" 214 include_no_matches_msg =
"""Include tag filename spec \"{}\" matched no files.""" 220 previous = doc.documentElement
226 if elt.tagName ==
'xacro:include' or elt.tagName ==
'include':
230 if elt.tagName ==
'include':
236 if elt.childNodes
and not (
len(elt.childNodes) == 1
and 237 elt.childNodes[0].nodeType == elt.TEXT_NODE):
242 print(deprecated_include_msg, file=sys.stderr)
246 filename_spec =
eval_text(elt.getAttribute(
'filename'), {})
247 if not os.path.isabs(filename_spec):
248 filename_spec = os.path.join(base_dir, filename_spec)
250 if re.search(
'[*[?]+', filename_spec):
252 filenames = sorted(glob.glob(filename_spec))
253 if len(filenames) == 0:
254 print(include_no_matches_msg.format(filename_spec), file=sys.stderr)
257 filenames = [filename_spec]
259 for filename
in filenames:
261 all_includes.append(filename)
263 with open(filename)
as f:
266 except Exception
as e:
268 "included file \"%s\" generated an error during XML parsing: %s" 269 % (filename, str(e)))
271 raise XacroException(
"included file \"%s\" could not be opened: %s" % (filename, str(e)))
275 elt.parentNode.insertBefore(c.cloneNode(deep=
True), elt)
278 for name, value
in included.documentElement.attributes.items():
279 if name.startswith(
'xmlns:'):
280 namespaces[name] = value
282 elt.parentNode.removeChild(elt)
290 for k, v
in namespaces.items():
291 doc.documentElement.setAttribute(k, v)
298 previous = doc.documentElement
301 if elt.tagName ==
'macro' or elt.tagName ==
'xacro:macro':
302 name = elt.getAttribute(
'name')
305 macros[
'xacro:' + name] = elt
307 elt.parentNode.removeChild(elt)
320 previous = doc.documentElement
323 if elt.tagName ==
'property' or elt.tagName ==
'xacro:property':
324 name = elt.getAttribute(
'name')
327 if elt.hasAttribute(
'value'):
328 value = elt.getAttribute(
'value')
333 bad = string.whitespace +
"${}" 341 sys.stderr.write(
'Property names may not have whitespace, ' +
342 '"{", "}", or "$" : "' + name +
'"')
346 elt.parentNode.removeChild(elt)
356 while lex.peek()
and lex.peek()[0] == lex.IGNORE:
362 if lex.peek()[0] == lex.NUMBER:
363 return float(lex.next()[1])
364 if lex.peek()[0] == lex.SYMBOL:
368 except KeyError
as ex:
370 if not (
isnumber(value)
or isinstance(value, _basestr)):
393 if lex.peek()[1] ==
'-':
397 if lex.peek()[0]
in [lex.NUMBER, lex.SYMBOL]:
399 if lex.peek()[0] == lex.LPAREN:
404 if lex.next()[0] != lex.RPAREN:
416 if lex.peek()[0]
in [lex.NUMBER, lex.SYMBOL, lex.LPAREN] \
417 or lex.peek()[1] ==
'-':
421 while lex.peek()
and lex.peek()[1]
in [
'*',
'/']:
426 result = float(result) * float(n)
428 result = float(result) / float(n)
439 if lex.peek()[0] == lex.OP:
441 if not op
in [
'+',
'-']:
446 result = -float(result)
449 while lex.peek()
and lex.peek()[1]
in [
'+',
'-']:
454 result = float(result) + float(n)
456 result = float(result) - float(n)
464 NUMBER=
r"(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?",
465 SYMBOL=
r"[a-zA-Z_]\w*",
472 def handle_extension(s):
476 lex =
QuickLexer(DOLLAR_DOLLAR_BRACE=
r"\$\$+\{",
477 EXPR=
r"\$\{[^\}]*\}",
478 EXTENSION=
r"\$\([^\)]*\)",
479 TEXT=
r"([^\$]|\$[^{(]|\$$)+")
482 if lex.peek()[0] == lex.EXPR:
483 results.append(handle_expr(lex.next()[1][2:-1]))
484 elif lex.peek()[0] == lex.EXTENSION:
485 results.append(handle_extension(lex.next()[1][2:-1]))
486 elif lex.peek()[0] == lex.TEXT:
487 results.append(lex.next()[1])
488 elif lex.peek()[0] == lex.DOLLAR_DOLLAR_BRACE:
489 results.append(lex.next()[1][1:])
490 return ''.join(map(str, results))
496 for at
in root.attributes.items():
498 root.setAttribute(at[0], result)
503 if node.nodeType == xml.dom.Node.ELEMENT_NODE:
504 if node.tagName
in macros:
505 body = macros[node.tagName].cloneNode(deep=
True)
506 params = body.getAttribute(
'params').split()
510 for param
in params[:]:
511 splitParam = param.split(
':=')
513 if len(splitParam) == 2:
514 defaultmap[splitParam[0]] = splitParam[1]
516 params.append(splitParam[0])
518 elif len(splitParam) != 1:
522 scoped =
Table(symbols)
523 for name, value
in node.attributes.items():
524 if not name
in params:
525 raise XacroException(
"Invalid parameter \"%s\" while expanding macro \"%s\"" %
526 (str(name), str(node.tagName)))
531 cloned = node.cloneNode(deep=
True)
533 block = cloned.firstChild
534 for param
in params[:]:
536 while block
and block.nodeType != xml.dom.Node.ELEMENT_NODE:
537 block = block.nextSibling
539 raise XacroException(
"Not enough blocks while evaluating macro %s" % str(node.tagName))
541 scoped[param] = block
542 block = block.nextSibling
545 for param
in params[:]:
546 if param[0] !=
'*' and param
in defaultmap:
547 scoped[param] = defaultmap[param]
551 raise XacroException(
"Parameters [%s] were not set for macro %s" %
552 (
",".join(params), str(node.tagName)))
557 node.parentNode.insertBefore(e, node)
558 node.parentNode.removeChild(node)
561 elif node.tagName ==
'xacro:arg':
562 name = node.getAttribute(
'name')
565 default = node.getAttribute(
'default')
566 if default
and name
not in substitution_args_context[
'arg']:
567 substitution_args_context[
'arg'][name] = default
569 node.parentNode.removeChild(node)
572 elif node.tagName ==
'insert_block' or node.tagName ==
'xacro:insert_block':
573 name = node.getAttribute(
'name')
575 if (
"**" + name)
in symbols:
577 block = symbols[
'**' + name]
580 node.parentNode.insertBefore(e.cloneNode(deep=
True), node)
581 node.parentNode.removeChild(node)
582 elif (
"*" + name)
in symbols:
584 block = symbols[
'*' + name]
586 node.parentNode.insertBefore(block.cloneNode(deep=
True), node)
587 node.parentNode.removeChild(node)
592 elif node.tagName
in [
'if',
'xacro:if',
'unless',
'xacro:unless']:
593 value =
eval_text(node.getAttribute(
'value'), symbols)
595 if value ==
'true': keep =
True 596 elif value ==
'false': keep =
False 597 else: keep = float(value)
599 raise XacroException(
"Xacro conditional evaluated to \"%s\". Acceptable evaluations are one of [\"1\",\"true\",\"0\",\"false\"]" % value)
600 if node.tagName
in [
'unless',
'xacro:unless']: keep =
not keep
603 node.parentNode.insertBefore(e.cloneNode(deep=
True), node)
605 node.parentNode.removeChild(node)
608 for at
in node.attributes.items():
610 node.setAttribute(at[0], result)
612 elif node.nodeType == xml.dom.Node.TEXT_NODE:
613 node.data =
eval_text(node.data, symbols)
626 eval_all(doc.documentElement, macros, symbols)
630 print(
"Usage: %s [-o <output>] <input>" %
'xacro.py')
631 print(
" %s --deps Prints dependencies" %
'xacro.py')
632 print(
" %s --includes Only evalutes includes" %
'xacro.py')
637 substitution_args_context[
'arg'] = context
640 if output_filename
is None:
643 return open(output_filename,
'w')
647 opts, args = getopt.gnu_getopt(sys.argv[1:],
"ho:", [
'deps',
'includes'])
648 except getopt.GetoptError
as err:
653 just_includes =
False 655 output_filename =
None 663 elif o ==
'--includes':
667 print(
"No input given")
677 except xml.parsers.expat.ExpatError:
678 sys.stderr.write(
"Expat parsing error. Check that:\n")
679 sys.stderr.write(
" - Your XML is correctly formed\n")
680 sys.stderr.write(
" - You have the xacro xmlns declaration: " +
681 "xmlns:xacro=\"http://www.ros.org/wiki/xacro\"\n")
682 sys.stderr.write(
"\n")
689 for inc
in all_includes:
690 sys.stdout.write(inc +
" ")
691 sys.stdout.write(
"\n")
697 banner = [xml.dom.minidom.Comment(c)
for c
in 698 [
" %s " % (
'=' * 83),
699 " | This document was autogenerated by xacro from %-30s | " % args[0],
700 " | EDITING THIS FILE BY HAND IS NOT RECOMMENDED %-30s | " %
"",
701 " %s " % (
'=' * 83)]]
702 first = doc.firstChild
703 for comment
in banner:
704 doc.insertBefore(comment, first)
706 open_output(output_filename).write(doc.toprettyxml(indent=
' '))
def process_includes(elt, macros=None, symbols=None)
def grab_properties(elt, table)
def eval_text(text, symbols)
def print_usage(exit_code=0)
def first_child_element(elt)
def eval_all(root, macros, symbols)
def open_output(output_filename)
def eval_factor(lex, symbols)
def set_substitution_args_context(context={})
def fixed_writexml(self, writer, indent="", addindent="", newl="")
def eval_expr(lex, symbols)
def resolve_args(arg_str, context=None, resolve_anon=True)
def eval_lit(lex, symbols)
def next_sibling_element(elt)
def eval_self_contained(doc)
def grab_macros(elt, macros)
def eval_term(lex, symbols)