16 #pragma GCC diagnostic push 17 #pragma GCC diagnostic ignored "-Wattributes" 35 std::vector<TreeNode::Ptr>& nodes,
59 current_path( filesystem::
path::getcwd() ),
66 current_path = filesystem::path::getcwd();
67 opened_documents.clear();
72 #pragma GCC diagnostic pop 91 filesystem::path file_path( filename );
103 doc->
Parse(xml_text.c_str(), xml_text.size());
113 sprintf(buffer,
"Error parsing the XML: %s", doc->
ErrorName() );
114 throw std::runtime_error(buffer);
121 include_node !=
nullptr;
125 filesystem::path file_path( include_node->Attribute(
"path") );
127 if( include_node->Attribute(
"ros_pkg") )
130 if( file_path.is_absolute() )
132 std::cout <<
"WARNING: <include path=\"...\"> containes an absolute path.\n" 133 <<
"Attribute [ros_pkg] will be ignored."<< std::endl;
137 file_path = filesystem::path( ros_pkg_path ) / file_path;
140 throw std::runtime_error(
"Using attribute [ros_pkg] in <include>, but this library was compiled " 141 "without ROS support. Recompile the BehaviorTree.CPP using catkin");
145 if( !file_path.is_absolute() )
147 file_path = current_path / file_path;
150 opened_documents.emplace_back(
new XMLDocument() );
152 doc->
LoadFile(file_path.str().c_str());
160 std::string tree_name;
161 if (bt_node->Attribute(
"ID"))
163 tree_name = bt_node->Attribute(
"ID");
168 tree_roots.insert( {tree_name, bt_node} );
176 auto StrEqual = [](
const char* str1,
const char* str2) ->
bool {
177 return strcmp(str1, str2) == 0;
180 auto ThrowError = [&](
int line_num,
const std::string& text) {
182 sprintf(buffer,
"Error at line %d: -> %s", line_num, text.c_str());
183 throw std::runtime_error( buffer );
186 auto ChildrenCount = [](
const XMLElement* parent_node) {
188 for (
auto node = parent_node->FirstChildElement(); node !=
nullptr;
189 node = node->NextSiblingElement())
199 if (!xml_root || !StrEqual(xml_root->
Name(),
"root"))
201 throw std::runtime_error(
"The XML must have a root node called <root>");
205 auto meta_sibling = meta_root ? meta_root->
NextSiblingElement(
"TreeNodesModel") :
nullptr;
209 ThrowError(meta_sibling->GetLineNum(),
" Only a single node <TreeNodesModel> is " 219 const char* name = node->
Name();
220 if (StrEqual(name,
"Action") || StrEqual(name,
"Decorator") ||
221 StrEqual(name,
"SubTree") || StrEqual(name,
"Condition"))
223 const char* ID = node->Attribute(
"ID");
226 ThrowError(node->GetLineNum(),
"Error at line %d: -> The attribute [ID] is " 235 std::function<void(const XMLElement*)> recursiveStep;
238 const int children_count = ChildrenCount(node);
239 const char* name = node->Name();
240 if (StrEqual(name,
"Decorator"))
242 if (children_count != 1)
244 ThrowError(node->GetLineNum(),
"The node <Decorator> must have exactly 1 child");
246 if (!node->Attribute(
"ID"))
248 ThrowError(node->GetLineNum(),
"The node <Decorator> must have the attribute " 252 else if (StrEqual(name,
"Action"))
254 if (children_count != 0)
256 ThrowError(node->GetLineNum(),
"The node <Action> must not have any child");
258 if (!node->Attribute(
"ID"))
260 ThrowError(node->GetLineNum(),
"The node <Action> must have the attribute [ID]");
263 else if (StrEqual(name,
"Condition"))
265 if (children_count != 0)
267 ThrowError(node->GetLineNum(),
"The node <Condition> must not have any child");
269 if (!node->Attribute(
"ID"))
271 ThrowError(node->GetLineNum(),
"The node <Condition> must have the attribute " 275 else if (StrEqual(name,
"Sequence") || StrEqual(name,
"SequenceStar") ||
276 StrEqual(name,
"Fallback") || StrEqual(name,
"FallbackStar"))
278 if (children_count == 0)
280 ThrowError(node->GetLineNum(),
"A Control node must have at least 1 child");
283 else if (StrEqual(name,
"SubTree"))
285 if (children_count > 0)
287 ThrowError(node->GetLineNum(),
"The <SubTree> node must have no children");
289 if (!node->Attribute(
"ID"))
291 ThrowError(node->GetLineNum(),
"The node <SubTree> must have the attribute [ID]");
298 for (
const auto& model : factory.manifests())
300 if (model.registration_ID == name)
306 for (
const auto& subtrees_it : tree_roots)
308 if (subtrees_it.first == name)
316 ThrowError(node->GetLineNum(), std::string(
"Node not recognized: ") + name);
320 for (
auto child = node->FirstChildElement(); child !=
nullptr;
321 child = child->NextSiblingElement())
323 recursiveStep(child);
327 std::vector<std::string> tree_names;
330 for (
auto bt_root = xml_root->
FirstChildElement(
"BehaviorTree"); bt_root !=
nullptr;
334 if (bt_root->Attribute(
"ID"))
336 tree_names.push_back(bt_root->Attribute(
"ID"));
338 if (ChildrenCount(bt_root) != 1)
340 ThrowError(bt_root->GetLineNum(),
"The node <BehaviorTree> must have exactly 1 child");
344 recursiveStep(bt_root->FirstChildElement());
348 if (xml_root->
Attribute(
"main_tree_to_execute"))
350 std::string main_tree = xml_root->
Attribute(
"main_tree_to_execute");
351 if (std::find(tree_names.begin(), tree_names.end(), main_tree) == tree_names.end())
353 throw std::runtime_error(
"The tree esecified in [main_tree_to_execute] can't be found");
360 throw std::runtime_error(
361 "If you don't specify the attribute [main_tree_to_execute], " 362 "Your file must contain a single BehaviorTree");
374 std::string main_tree_ID;
375 if (xml_root->
Attribute(
"main_tree_to_execute"))
377 main_tree_ID = xml_root->
Attribute(
"main_tree_to_execute");
384 throw std::runtime_error(
"[main_tree_to_execute] was not specified correctly");
387 auto root_element =
_p->
tree_roots[main_tree_ID]->FirstChildElement();
394 std::vector<TreeNode::Ptr>& nodes,
397 std::function<TreeNode::Ptr(const XMLElement*, const TreeNode::Ptr&)> recursiveStep;
399 recursiveStep = [&](
const XMLElement* element,
402 TreeNode::Ptr child_node = buildNodeFromElement(element, parent);
403 nodes.push_back(child_node);
409 const auto& name = child_node->
name();
410 auto subtree_elem = tree_roots[name]->FirstChildElement();
411 buildTreeRecursively(subtree_elem, nodes, child_node);
417 recursiveStep(child_element, child_node);
424 TreeNode::Ptr root = recursiveStep(root_element, root_parent );
431 const std::string element_name = element->
Name();
433 std::string node_name;
436 if (element_name ==
"Action" ||
437 element_name ==
"Decorator" ||
438 element_name ==
"Condition")
446 const char* attr_alias = element->
Attribute(
"name");
449 node_name = attr_alias;
456 if (element_name ==
"SubTree")
463 const std::string attribute_name = att->Name();
464 if (attribute_name !=
"ID" && attribute_name !=
"name")
466 params[attribute_name] = att->Value();
472 if( factory.builders().count(ID) != 0)
474 child_node = factory.instantiateTreeNode(ID, node_name, params, blackboard);
476 else if( tree_roots.count(ID) != 0) {
480 throw std::runtime_error( ID +
" is not a registered node, nor a Subtree");
488 control_parent->
addChild(child_node.get());
491 if (decorator_parent)
493 decorator_parent->
setChild(child_node.get());
507 std::vector<TreeNode::Ptr> nodes;
510 return Tree(root.get(), nodes);
519 std::vector<TreeNode::Ptr> nodes;
521 return Tree(root.get(), nodes);
526 bool compact_representation)
540 std::function<void(const TreeNode*, XMLElement* parent)> recursiveVisitor;
542 recursiveVisitor = [&recursiveVisitor, &doc, compact_representation,
544 std::string node_type =
toStr(node->type());
545 std::string node_ID = node->registrationName();
546 std::string node_name = node->name();
552 else if (compact_representation)
554 for (
const auto& model : factory.
manifests())
556 if (model.registration_ID == node_ID)
564 XMLElement* element = doc.NewElement(node_type.c_str());
565 if (node_type != node_ID && !node_ID.empty())
569 if (node_type != node_name && !node_name.empty() && node_name != node_ID)
574 for (
const auto& param : node->initializationParameters())
576 element->
SetAttribute(param.first.c_str(), param.second.c_str());
579 parent->InsertEndChild(element);
581 if (
auto control = dynamic_cast<const BT::ControlNode*>(node))
583 for (
const auto& child : control->children())
585 recursiveVisitor(static_cast<const TreeNode*>(child), element);
588 else if (
auto decorator = dynamic_cast<const BT::DecoratorNode*>(node))
590 recursiveVisitor(decorator->child(), element);
594 recursiveVisitor(root_node, bt_root);
603 if( factory.
builtinNodes().count( model.registration_ID ) != 0)
613 element->
SetAttribute(
"ID", model.registration_ID.c_str());
615 for (
auto& param : model.required_parameters)
618 param.second.c_str() );
626 return std::string(printer.
CStr(), printer.
CStrSize() - 1);
Pimpl(const BehaviorTreeFactory &fact)
bool Error() const
Return true if there was an error parsing the document.
const XMLElement * FirstChildElement(const char *name=0) const
const std::string & name() const
void verifyXML(const XMLDocument *doc) const
XMLError Parse(const char *xml, size_t nBytes=(size_t)(-1))
XMLError LoadFile(const char *filename)
static raw_event_t * buffer
const XMLElement * NextSiblingElement(const char *name=0) const
Get the next (right) sibling element of this node, with an optionally supplied name.
filesystem::path current_path
TreeNode::Ptr buildNodeFromElement(const XMLElement *element, TreeNode::Ptr parent)
const std::string xml_text
std::shared_ptr< Blackboard > Ptr
const std::set< std::string > & builtinNodes() const
std::string writeXML(const BehaviorTreeFactory &factory, const TreeNode *root_node, bool compact_representation=false)
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
XMLElement * NewElement(const char *name)
const char * toStr(const BT::NodeStatus &status, bool colored=false)
toStr converts NodeStatus to string. Optionally colored.
XMLElement * RootElement()
const XMLAttribute * Next() const
The next attribute in the list.
void loadDocImpl(XMLDocument *doc)
std::unordered_map< std::string, std::string > NodeParameters
const char * Attribute(const char *name, const char *value=0) const
void setChild(TreeNode *child)
void loadFromFile(const std::string &filename)
Tree buildTreeFromFile(const BehaviorTreeFactory &factory, const std::string &filename, const Blackboard::Ptr &blackboard=Blackboard::Ptr())
const BehaviorTreeFactory & factory
XMLNode * InsertFirstChild(XMLNode *addThis)
TreeNode::Ptr instantiateTree(std::vector< TreeNode::Ptr > &nodes, const Blackboard::Ptr &blackboard)
Simple class for manipulating paths on Linux/Windows/Mac OS.
ROSLIB_DECL std::string getPath(const std::string &package_name)
std::list< std::unique_ptr< XMLDocument > > opened_documents
static volatile int count
void loadFromText(const std::string &xml_text)
void addChild(TreeNode *child)
std::map< std::string, const XMLElement * > tree_roots
XMLParser(const BehaviorTreeFactory &factory)
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
std::shared_ptr< TreeNode > Ptr
TreeNode::Ptr buildTreeRecursively(const XMLElement *root_element, std::vector< TreeNode::Ptr > &nodes, const TreeNode::Ptr &root_parent)
void Print(XMLPrinter *streamer=0) const
Blackboard::Ptr blackboard
std::basic_string< CharT, Traits > to_string(basic_string_view< CharT, Traits > v)
const char * ErrorName() const
XMLNode * InsertEndChild(XMLNode *addThis)
const std::vector< TreeNodeManifest > & manifests() const
Manifests of all the registered TreeNodes.
Tree buildTreeFromText(const BehaviorTreeFactory &factory, const std::string &text, const Blackboard::Ptr &blackboard=Blackboard::Ptr())
const char * CStr() const
const char * Name() const
Get the name of an element (which is the Value() of the node.)