00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <functional>
00014 #include <list>
00015
00016 #pragma GCC diagnostic push
00017 #pragma GCC diagnostic ignored "-Wattributes"
00018 #include "behaviortree_cpp/xml_parsing.h"
00019 #include "tinyXML2/tinyxml2.h"
00020 #include "filesystem/path.h"
00021
00022 #ifdef USING_ROS
00023 #include <ros/package.h>
00024 #endif
00025
00026 namespace BT
00027 {
00028
00029 using namespace tinyxml2;
00030
00031
00032 struct XMLParser::Pimpl
00033 {
00034 TreeNode::Ptr buildTreeRecursively(const XMLElement* root_element,
00035 std::vector<TreeNode::Ptr>& nodes,
00036 const TreeNode::Ptr& root_parent);
00037
00038 TreeNode::Ptr buildNodeFromElement(const XMLElement* element,
00039 TreeNode::Ptr parent);
00040
00041 void loadDocImpl(XMLDocument *doc);
00042
00043 void verifyXML(const XMLDocument* doc) const;
00044
00045 std::list< std::unique_ptr<XMLDocument>> opened_documents;
00046
00047 std::map<std::string,const XMLElement*> tree_roots;
00048
00049 const BehaviorTreeFactory& factory;
00050
00051 filesystem::path current_path;
00052
00053 int suffix_count;
00054
00055 Blackboard::Ptr blackboard;
00056
00057 Pimpl(const BehaviorTreeFactory &fact):
00058 factory(fact),
00059 current_path( filesystem::path::getcwd() ),
00060 suffix_count(0)
00061 {}
00062
00063 void clear()
00064 {
00065 suffix_count = 0;
00066 current_path = filesystem::path::getcwd();
00067 opened_documents.clear();
00068 tree_roots.clear();
00069 }
00070
00071 };
00072 #pragma GCC diagnostic pop
00073
00074 XMLParser::XMLParser(const BehaviorTreeFactory &factory) : _p( new Pimpl(factory) )
00075 {
00076 }
00077
00078 XMLParser::~XMLParser()
00079 {
00080 delete _p;
00081 }
00082
00083 void XMLParser::loadFromFile(const std::string& filename)
00084 {
00085 _p->clear();
00086 _p->opened_documents.emplace_back( new XMLDocument() );
00087
00088 XMLDocument* doc = _p->opened_documents.back().get();
00089 doc->LoadFile(filename.c_str());
00090
00091 filesystem::path file_path( filename );
00092 _p->current_path = file_path.parent_path().make_absolute();
00093
00094 _p->loadDocImpl( doc );
00095 }
00096
00097 void XMLParser::loadFromText(const std::string& xml_text)
00098 {
00099 _p->clear();
00100 _p->opened_documents.emplace_back( new XMLDocument() );
00101
00102 XMLDocument* doc = _p->opened_documents.back().get();
00103 doc->Parse(xml_text.c_str(), xml_text.size());
00104
00105 _p->loadDocImpl( doc );
00106 }
00107
00108 void XMLParser::Pimpl::loadDocImpl(XMLDocument* doc)
00109 {
00110 if (doc->Error())
00111 {
00112 char buffer[200];
00113 sprintf(buffer, "Error parsing the XML: %s", doc->ErrorName() );
00114 throw std::runtime_error(buffer);
00115 }
00116
00117 const XMLElement* xml_root = doc->RootElement();
00118
00119
00120 for (auto include_node = xml_root->FirstChildElement("include");
00121 include_node != nullptr;
00122 include_node = include_node->NextSiblingElement("include"))
00123 {
00124
00125 filesystem::path file_path( include_node->Attribute("path") );
00126
00127 if( include_node->Attribute("ros_pkg") )
00128 {
00129 #ifdef USING_ROS
00130 if( file_path.is_absolute() )
00131 {
00132 std::cout << "WARNING: <include path=\"...\"> containes an absolute path.\n"
00133 << "Attribute [ros_pkg] will be ignored."<< std::endl;
00134 }
00135 else {
00136 auto ros_pkg_path = ros::package::getPath( include_node->Attribute("ros_pkg") );
00137 file_path = filesystem::path( ros_pkg_path ) / file_path;
00138 }
00139 #else
00140 throw std::runtime_error("Using attribute [ros_pkg] in <include>, but this library was compiled "
00141 "without ROS support. Recompile the BehaviorTree.CPP using catkin");
00142 #endif
00143 }
00144
00145 if( !file_path.is_absolute() )
00146 {
00147 file_path = current_path / file_path;
00148 }
00149
00150 opened_documents.emplace_back( new XMLDocument() );
00151 XMLDocument* doc = opened_documents.back().get();
00152 doc->LoadFile(file_path.str().c_str());
00153 loadDocImpl( doc );
00154 }
00155
00156 for (auto bt_node = xml_root->FirstChildElement("BehaviorTree");
00157 bt_node != nullptr;
00158 bt_node = bt_node->NextSiblingElement("BehaviorTree"))
00159 {
00160 std::string tree_name;
00161 if (bt_node->Attribute("ID"))
00162 {
00163 tree_name = bt_node->Attribute("ID");
00164 }
00165 else{
00166 tree_name = "BehaviorTree_" + std::to_string( suffix_count++ );
00167 }
00168 tree_roots.insert( {tree_name, bt_node} );
00169 }
00170 verifyXML(doc);
00171 }
00172
00173 void XMLParser::Pimpl::verifyXML(const XMLDocument* doc) const
00174 {
00175
00176 auto StrEqual = [](const char* str1, const char* str2) -> bool {
00177 return strcmp(str1, str2) == 0;
00178 };
00179
00180 auto ThrowError = [&](int line_num, const std::string& text) {
00181 char buffer[256];
00182 sprintf(buffer, "Error at line %d: -> %s", line_num, text.c_str());
00183 throw std::runtime_error( buffer );
00184 };
00185
00186 auto ChildrenCount = [](const XMLElement* parent_node) {
00187 int count = 0;
00188 for (auto node = parent_node->FirstChildElement(); node != nullptr;
00189 node = node->NextSiblingElement())
00190 {
00191 count++;
00192 }
00193 return count;
00194 };
00195
00196
00197 const XMLElement* xml_root = doc->RootElement();
00198
00199 if (!xml_root || !StrEqual(xml_root->Name(), "root"))
00200 {
00201 throw std::runtime_error("The XML must have a root node called <root>");
00202 }
00203
00204 auto meta_root = xml_root->FirstChildElement("TreeNodesModel");
00205 auto meta_sibling = meta_root ? meta_root->NextSiblingElement("TreeNodesModel") : nullptr;
00206
00207 if (meta_sibling)
00208 {
00209 ThrowError(meta_sibling->GetLineNum(), " Only a single node <TreeNodesModel> is "
00210 "supported");
00211 }
00212 if (meta_root)
00213 {
00214
00215
00216 for (auto node = xml_root->FirstChildElement(); node != nullptr;
00217 node = node->NextSiblingElement())
00218 {
00219 const char* name = node->Name();
00220 if (StrEqual(name, "Action") || StrEqual(name, "Decorator") ||
00221 StrEqual(name, "SubTree") || StrEqual(name, "Condition"))
00222 {
00223 const char* ID = node->Attribute("ID");
00224 if (!ID)
00225 {
00226 ThrowError(node->GetLineNum(), "Error at line %d: -> The attribute [ID] is "
00227 "mandatory");
00228 }
00229 }
00230 }
00231 }
00232
00233
00234
00235 std::function<void(const XMLElement*)> recursiveStep;
00236
00237 recursiveStep = [&](const XMLElement* node) {
00238 const int children_count = ChildrenCount(node);
00239 const char* name = node->Name();
00240 if (StrEqual(name, "Decorator"))
00241 {
00242 if (children_count != 1)
00243 {
00244 ThrowError(node->GetLineNum(), "The node <Decorator> must have exactly 1 child");
00245 }
00246 if (!node->Attribute("ID"))
00247 {
00248 ThrowError(node->GetLineNum(), "The node <Decorator> must have the attribute "
00249 "[ID]");
00250 }
00251 }
00252 else if (StrEqual(name, "Action"))
00253 {
00254 if (children_count != 0)
00255 {
00256 ThrowError(node->GetLineNum(), "The node <Action> must not have any child");
00257 }
00258 if (!node->Attribute("ID"))
00259 {
00260 ThrowError(node->GetLineNum(), "The node <Action> must have the attribute [ID]");
00261 }
00262 }
00263 else if (StrEqual(name, "Condition"))
00264 {
00265 if (children_count != 0)
00266 {
00267 ThrowError(node->GetLineNum(), "The node <Condition> must not have any child");
00268 }
00269 if (!node->Attribute("ID"))
00270 {
00271 ThrowError(node->GetLineNum(), "The node <Condition> must have the attribute "
00272 "[ID]");
00273 }
00274 }
00275 else if (StrEqual(name, "Sequence") || StrEqual(name, "SequenceStar") ||
00276 StrEqual(name, "Fallback") || StrEqual(name, "FallbackStar"))
00277 {
00278 if (children_count == 0)
00279 {
00280 ThrowError(node->GetLineNum(), "A Control node must have at least 1 child");
00281 }
00282 }
00283 else if (StrEqual(name, "SubTree"))
00284 {
00285 if (children_count > 0)
00286 {
00287 ThrowError(node->GetLineNum(), "The <SubTree> node must have no children");
00288 }
00289 if (!node->Attribute("ID"))
00290 {
00291 ThrowError(node->GetLineNum(), "The node <SubTree> must have the attribute [ID]");
00292 }
00293 }
00294 else
00295 {
00296
00297 bool found = false;
00298 for (const auto& model : factory.manifests())
00299 {
00300 if (model.registration_ID == name)
00301 {
00302 found = true;
00303 break;
00304 }
00305 }
00306 for (const auto& subtrees_it : tree_roots)
00307 {
00308 if (subtrees_it.first == name)
00309 {
00310 found = true;
00311 break;
00312 }
00313 }
00314 if (!found)
00315 {
00316 ThrowError(node->GetLineNum(), std::string("Node not recognized: ") + name);
00317 }
00318 }
00319
00320 for (auto child = node->FirstChildElement(); child != nullptr;
00321 child = child->NextSiblingElement())
00322 {
00323 recursiveStep(child);
00324 }
00325 };
00326
00327 std::vector<std::string> tree_names;
00328 int tree_count = 0;
00329
00330 for (auto bt_root = xml_root->FirstChildElement("BehaviorTree"); bt_root != nullptr;
00331 bt_root = bt_root->NextSiblingElement("BehaviorTree"))
00332 {
00333 tree_count++;
00334 if (bt_root->Attribute("ID"))
00335 {
00336 tree_names.push_back(bt_root->Attribute("ID"));
00337 }
00338 if (ChildrenCount(bt_root) != 1)
00339 {
00340 ThrowError(bt_root->GetLineNum(), "The node <BehaviorTree> must have exactly 1 child");
00341 }
00342 else
00343 {
00344 recursiveStep(bt_root->FirstChildElement());
00345 }
00346 }
00347
00348 if (xml_root->Attribute("main_tree_to_execute"))
00349 {
00350 std::string main_tree = xml_root->Attribute("main_tree_to_execute");
00351 if (std::find(tree_names.begin(), tree_names.end(), main_tree) == tree_names.end())
00352 {
00353 throw std::runtime_error("The tree esecified in [main_tree_to_execute] can't be found");
00354 }
00355 }
00356 else
00357 {
00358 if (tree_count != 1)
00359 {
00360 throw std::runtime_error(
00361 "If you don't specify the attribute [main_tree_to_execute], "
00362 "Your file must contain a single BehaviorTree");
00363 }
00364 }
00365 }
00366
00367 TreeNode::Ptr XMLParser::instantiateTree(std::vector<TreeNode::Ptr>& nodes,
00368 const Blackboard::Ptr& blackboard)
00369 {
00370 nodes.clear();
00371
00372 XMLElement* xml_root = _p->opened_documents.front()->RootElement();
00373
00374 std::string main_tree_ID;
00375 if (xml_root->Attribute("main_tree_to_execute"))
00376 {
00377 main_tree_ID = xml_root->Attribute("main_tree_to_execute");
00378 }
00379 else if( _p->tree_roots.size() == 1)
00380 {
00381 main_tree_ID = _p->tree_roots.begin()->first;
00382 }
00383 else{
00384 throw std::runtime_error("[main_tree_to_execute] was not specified correctly");
00385 }
00386
00387 auto root_element = _p->tree_roots[main_tree_ID]->FirstChildElement();
00388
00389 _p->blackboard = blackboard;
00390 return _p->buildTreeRecursively(root_element, nodes, TreeNode::Ptr());
00391 }
00392
00393 TreeNode::Ptr BT::XMLParser::Pimpl::buildTreeRecursively(const XMLElement* root_element,
00394 std::vector<TreeNode::Ptr>& nodes,
00395 const TreeNode::Ptr& root_parent)
00396 {
00397 std::function<TreeNode::Ptr(const XMLElement*, const TreeNode::Ptr&)> recursiveStep;
00398
00399 recursiveStep = [&](const XMLElement* element,
00400 const TreeNode::Ptr& parent) -> TreeNode::Ptr
00401 {
00402 TreeNode::Ptr child_node = buildNodeFromElement(element, parent);
00403 nodes.push_back(child_node);
00404
00405 DecoratorSubtreeNode* subtree_node = dynamic_cast<DecoratorSubtreeNode*>(child_node.get());
00406
00407 if (subtree_node)
00408 {
00409 const auto& name = child_node->name();
00410 auto subtree_elem = tree_roots[name]->FirstChildElement();
00411 buildTreeRecursively(subtree_elem, nodes, child_node);
00412 }
00413
00414 for (auto child_element = element->FirstChildElement(); child_element;
00415 child_element = child_element->NextSiblingElement())
00416 {
00417 recursiveStep(child_element, child_node);
00418 }
00419
00420 return child_node;
00421 };
00422
00423
00424 TreeNode::Ptr root = recursiveStep(root_element, root_parent );
00425 return root;
00426 }
00427
00428 TreeNode::Ptr XMLParser::Pimpl::buildNodeFromElement(const XMLElement *element,
00429 TreeNode::Ptr parent)
00430 {
00431 const std::string element_name = element->Name();
00432 std::string ID;
00433 std::string node_name;
00434 NodeParameters params;
00435
00436 if (element_name == "Action" ||
00437 element_name == "Decorator" ||
00438 element_name == "Condition")
00439 {
00440 ID = element->Attribute("ID");
00441 }
00442 else
00443 {
00444 ID = element_name;
00445 }
00446 const char* attr_alias = element->Attribute("name");
00447 if (attr_alias)
00448 {
00449 node_name = attr_alias;
00450 }
00451 else
00452 {
00453 node_name = ID;
00454 }
00455
00456 if (element_name == "SubTree")
00457 {
00458 node_name = element->Attribute("ID");
00459 }
00460
00461 for (const XMLAttribute* att = element->FirstAttribute(); att; att = att->Next())
00462 {
00463 const std::string attribute_name = att->Name();
00464 if (attribute_name != "ID" && attribute_name != "name")
00465 {
00466 params[attribute_name] = att->Value();
00467 }
00468 }
00469
00470 TreeNode::Ptr child_node;
00471
00472 if( factory.builders().count(ID) != 0)
00473 {
00474 child_node = factory.instantiateTreeNode(ID, node_name, params, blackboard);
00475 }
00476 else if( tree_roots.count(ID) != 0) {
00477 child_node = std::unique_ptr<TreeNode>( new DecoratorSubtreeNode(node_name) );
00478 }
00479 else{
00480 throw std::runtime_error( ID + " is not a registered node, nor a Subtree");
00481 }
00482
00483 if (parent)
00484 {
00485 ControlNode* control_parent = dynamic_cast<ControlNode*>(parent.get());
00486 if (control_parent)
00487 {
00488 control_parent->addChild(child_node.get());
00489 }
00490 DecoratorNode* decorator_parent = dynamic_cast<DecoratorNode*>(parent.get());
00491 if (decorator_parent)
00492 {
00493 decorator_parent->setChild(child_node.get());
00494 }
00495 }
00496
00497 return child_node;
00498 }
00499
00500
00501 Tree buildTreeFromText(const BehaviorTreeFactory& factory, const std::string& text,
00502 const Blackboard::Ptr& blackboard)
00503 {
00504 XMLParser parser(factory);
00505 parser.loadFromText(text);
00506
00507 std::vector<TreeNode::Ptr> nodes;
00508 auto root = parser.instantiateTree(nodes, blackboard);
00509
00510 return Tree(root.get(), nodes);
00511 }
00512
00513 Tree buildTreeFromFile(const BehaviorTreeFactory& factory, const std::string& filename,
00514 const Blackboard::Ptr& blackboard)
00515 {
00516 XMLParser parser(factory);
00517 parser.loadFromFile(filename);
00518
00519 std::vector<TreeNode::Ptr> nodes;
00520 auto root = parser.instantiateTree(nodes, blackboard);
00521 return Tree(root.get(), nodes);
00522 }
00523
00524 std::string writeXML(const BehaviorTreeFactory& factory,
00525 const TreeNode* root_node,
00526 bool compact_representation)
00527 {
00528 using namespace tinyxml2;
00529
00530 XMLDocument doc;
00531
00532 XMLElement* rootXML = doc.NewElement("root");
00533 doc.InsertFirstChild(rootXML);
00534
00535 if (root_node)
00536 {
00537 XMLElement* bt_root = doc.NewElement("BehaviorTree");
00538 rootXML->InsertEndChild(bt_root);
00539
00540 std::function<void(const TreeNode*, XMLElement* parent)> recursiveVisitor;
00541
00542 recursiveVisitor = [&recursiveVisitor, &doc, compact_representation,
00543 &factory](const TreeNode* node, XMLElement* parent) -> void {
00544 std::string node_type = toStr(node->type());
00545 std::string node_ID = node->registrationName();
00546 std::string node_name = node->name();
00547
00548 if (node->type() == NodeType::CONTROL)
00549 {
00550 node_type = node_ID;
00551 }
00552 else if (compact_representation)
00553 {
00554 for (const auto& model : factory.manifests())
00555 {
00556 if (model.registration_ID == node_ID)
00557 {
00558 node_type = node_ID;
00559 break;
00560 }
00561 }
00562 }
00563
00564 XMLElement* element = doc.NewElement(node_type.c_str());
00565 if (node_type != node_ID && !node_ID.empty())
00566 {
00567 element->SetAttribute("ID", node_ID.c_str());
00568 }
00569 if (node_type != node_name && !node_name.empty() && node_name != node_ID)
00570 {
00571 element->SetAttribute("name", node_name.c_str());
00572 }
00573
00574 for (const auto& param : node->initializationParameters())
00575 {
00576 element->SetAttribute(param.first.c_str(), param.second.c_str());
00577 }
00578
00579 parent->InsertEndChild(element);
00580
00581 if (auto control = dynamic_cast<const BT::ControlNode*>(node))
00582 {
00583 for (const auto& child : control->children())
00584 {
00585 recursiveVisitor(static_cast<const TreeNode*>(child), element);
00586 }
00587 }
00588 else if (auto decorator = dynamic_cast<const BT::DecoratorNode*>(node))
00589 {
00590 recursiveVisitor(decorator->child(), element);
00591 }
00592 };
00593
00594 recursiveVisitor(root_node, bt_root);
00595 }
00596
00597
00598 XMLElement* model_root = doc.NewElement("TreeNodesModel");
00599 rootXML->InsertEndChild(model_root);
00600
00601 for (auto& model : factory.manifests())
00602 {
00603 if( factory.builtinNodes().count( model.registration_ID ) != 0)
00604 {
00605 continue;
00606 }
00607
00608 if (model.type == NodeType::CONTROL)
00609 {
00610 continue;
00611 }
00612 XMLElement* element = doc.NewElement(toStr(model.type));
00613 element->SetAttribute("ID", model.registration_ID.c_str());
00614
00615 for (auto& param : model.required_parameters)
00616 {
00617 element->SetAttribute( param.first.c_str(),
00618 param.second.c_str() );
00619 }
00620
00621 model_root->InsertEndChild(element);
00622 }
00623
00624 XMLPrinter printer;
00625 doc.Print(&printer);
00626 return std::string(printer.CStr(), printer.CStrSize() - 1);
00627 }
00628
00629
00630 }