4646#include " behaviortree_cpp/xml_parsing.h"
4747
4848#include < filesystem>
49+ #include < iterator>
4950#include < map>
5051#include < unordered_map>
5152
@@ -245,6 +246,25 @@ struct XMLParser::PImpl
245246
246247 void loadDocImpl (XMLDocument* doc, bool add_includes);
247248
249+ // Load the document just appended to opened_documents. A document that is
250+ // rejected (XML error, invalid tree) registers no tree, so forget it again:
251+ // it would otherwise remain the "first opened document" that
252+ // instantiateTree() reads main_tree_to_execute from, and a document that
253+ // did not parse has no root element at all.
254+ void loadLastDocImpl (bool add_includes)
255+ {
256+ const auto doc_it = std::prev (opened_documents.end ());
257+ try
258+ {
259+ loadDocImpl (doc_it->get (), add_includes);
260+ }
261+ catch (...)
262+ {
263+ opened_documents.erase (doc_it);
264+ throw ;
265+ }
266+ }
267+
248268 std::list<std::unique_ptr<XMLDocument> > opened_documents;
249269 std::map<std::string, const XMLElement*> tree_roots;
250270 std::unordered_map<std::string, std::string> tree_sources;
@@ -304,7 +324,7 @@ void XMLParser::loadFromFile(const std::filesystem::path& filepath, bool add_inc
304324 _p->current_path = std::filesystem::absolute (filepath.parent_path ());
305325 _p->include_stack = { IncludeKey (std::filesystem::absolute (filepath)) };
306326
307- _p->loadDocImpl (doc, add_includes);
327+ _p->loadLastDocImpl ( add_includes);
308328}
309329
310330void XMLParser::loadFromText (const std::string& xml_text, bool add_includes)
@@ -315,7 +335,7 @@ void XMLParser::loadFromText(const std::string& xml_text, bool add_includes)
315335 doc->Parse (xml_text.c_str (), xml_text.size ());
316336
317337 _p->include_stack .clear ();
318- _p->loadDocImpl (doc, add_includes);
338+ _p->loadLastDocImpl ( add_includes);
319339}
320340
321341std::vector<std::string> XMLParser::registeredBehaviorTrees () const
@@ -448,7 +468,7 @@ void XMLParser::PImpl::loadDocImpl(XMLDocument* doc, bool add_includes)
448468
449469 include_stack.push_back (std::move (include_key));
450470 next_doc->LoadFile (file_path.string ().c_str ());
451- loadDocImpl (next_doc, add_includes);
471+ loadLastDocImpl ( add_includes);
452472 include_stack.pop_back ();
453473
454474 // reset current path to the previous value
@@ -745,6 +765,10 @@ Tree XMLParser::instantiateTree(const Blackboard::Ptr& root_blackboard,
745765 // or the one in the FIRST document opened
746766 if (main_tree_ID.empty ())
747767 {
768+ if (_p->opened_documents .empty ())
769+ {
770+ throw RuntimeError (" XMLParser::instantiateTree: no XML document was loaded" );
771+ }
748772 XMLElement* first_xml_root = _p->opened_documents .front ()->RootElement ();
749773
750774 if (auto main_tree_attribute = first_xml_root->Attribute (" main_tree_to_execute" ))
0 commit comments