@@ -429,119 +429,75 @@ void VerifyXML(const std::string& xml_text,
429429 const std::string ID = node->Attribute (" ID" ) ? node->Attribute (" ID" ) : " " ;
430430 const int line_number = node->GetLineNum ();
431431
432- if (name == " Decorator" )
432+ // Precondition: built-in XML element types must define attribute [ID]
433+ const bool is_builtin =
434+ (name == " Decorator" || name == " Action" || name == " Condition" ||
435+ name == " Control" || name == " SubTree" );
436+ if (is_builtin && ID.empty ())
433437 {
434- if (children_count != 1 )
435- {
436- ThrowError (line_number, " The tag <Decorator> must have exactly 1 "
437- " child" );
438- }
439- if (ID.empty ())
440- {
441- ThrowError (line_number, " The tag <Decorator> must have the "
442- " attribute [ID]" );
443- }
444- }
445- else if (name == " Action" )
446- {
447- if (children_count != 0 )
448- {
449- ThrowError (line_number, " The tag <Action> must not have any "
450- " child" );
451- }
452- if (ID.empty ())
453- {
454- ThrowError (line_number, " The tag <Action> must have the "
455- " attribute [ID]" );
456- }
438+ ThrowError (line_number,
439+ std::string (" The tag <" ) + name + " > must have the attribute [ID]" );
457440 }
458- else if (name == " Condition" )
441+
442+ if (name == " BehaviorTree" )
459443 {
460- if (children_count != 0 )
461- {
462- ThrowError (line_number, " The tag <Condition> must not have any "
463- " child" );
464- }
465- if (ID.empty ())
444+ if (ID.empty () && behavior_tree_count > 1 )
466445 {
467- ThrowError (line_number, " The tag <Condition> must have the "
468- " attribute [ID]" );
446+ ThrowError (line_number, " The tag <BehaviorTree> must have the attribute [ID]" );
469447 }
470- }
471- else if (name == " Control" )
472- {
473- if (children_count == 0 )
448+ if (registered_nodes.count (ID) != 0 )
474449 {
475- ThrowError (line_number, " The tag <Control > must have at least 1 "
476- " child " );
450+ ThrowError (line_number, " The attribute [ID] of tag <BehaviorTree > must not use "
451+ " the name of a registered Node " );
477452 }
478- if (ID. empty () )
453+ if (children_count != 1 )
479454 {
480- ThrowError (line_number, " The tag <Control> must have the "
481- " attribute [ID] " );
455+ ThrowError (line_number, " The tag <BehaviorTree> with ID ' " + ID +
456+ " ' must have exactly 1 child " );
482457 }
483458 }
484459 else if (name == " SubTree" )
485460 {
486461 if (children_count != 0 )
487462 {
488- ThrowError (line_number, " <SubTree> should not have any child" );
489- }
490- if (ID.empty ())
491- {
492- ThrowError (line_number, " The tag <SubTree> must have the "
493- " attribute [ID]" );
463+ ThrowError (line_number,
464+ " <SubTree> with ID '" + ID + " ' should not have any child" );
494465 }
495466 if (registered_nodes.count (ID) != 0 )
496467 {
497- ThrowError (line_number, " The attribute [ID] of tag <SubTree> must "
498- " not use the name of a registered Node" );
499- }
500- }
501- else if (name == " BehaviorTree" )
502- {
503- if (ID.empty () && behavior_tree_count > 1 )
504- {
505- ThrowError (line_number, " The tag <BehaviorTree> must have the "
506- " attribute [ID]" );
507- }
508- if (children_count != 1 )
509- {
510- ThrowError (line_number, " The tag <BehaviorTree> must have exactly 1 "
511- " child" );
512- }
513- if (registered_nodes.count (ID) != 0 )
514- {
515- ThrowError (line_number, " The attribute [ID] of tag <BehaviorTree> "
516- " must not use the name of a registered Node" );
468+ ThrowError (line_number, " The attribute [ID] of tag <SubTree> must not use the "
469+ " name of a registered Node" );
517470 }
518471 }
519472 else
520473 {
521- // search in the factory and the list of subtrees
522- const auto search = registered_nodes.find (name);
474+ // use ID for builtin node types, otherwise use the element name
475+ const auto search = registered_nodes.find (is_builtin ? ID : name);
523476 bool found = (search != registered_nodes.end ());
524477 if (!found)
525478 {
526479 ThrowError (line_number, std::string (" Node not recognized: " ) + name);
527480 }
528481
529- if (search->second == NodeType::DECORATOR)
482+ const auto node_type = search->second ;
483+ const std::string& registered_name = search->first ;
484+
485+ if (node_type == NodeType::DECORATOR)
530486 {
531487 if (children_count != 1 )
532488 {
533- ThrowError (line_number,
534- std::string ( " The node < " ) + name + " > must have exactly 1 child" );
489+ ThrowError (line_number, std::string ( " The node ' " ) + registered_name +
490+ " ' must have exactly 1 child" );
535491 }
536492 }
537- else if (search-> second == NodeType::CONTROL)
493+ else if (node_type == NodeType::CONTROL)
538494 {
539495 if (children_count == 0 )
540496 {
541- ThrowError (line_number,
542- std::string ( " The node < " ) + name + " > must have 1 or more children" );
497+ ThrowError (line_number, std::string ( " The node ' " ) + registered_name +
498+ " ' must have 1 or more children" );
543499 }
544- if (name == " ReactiveSequence" )
500+ if (registered_name == " ReactiveSequence" )
545501 {
546502 size_t async_count = 0 ;
547503 for (auto child = node->FirstChildElement (); child != nullptr ;
@@ -563,13 +519,29 @@ void VerifyXML(const std::string& xml_text,
563519 ++async_count;
564520 if (async_count > 1 )
565521 {
566- ThrowError (line_number, std::string (" A ReactiveSequence cannot have more "
567- " than one async child." ));
522+ ThrowError (line_number, std::string (" A ReactiveSequence cannot have "
523+ " more than one async child." ));
568524 }
569525 }
570526 }
571527 }
572528 }
529+ else if (node_type == NodeType::ACTION)
530+ {
531+ if (children_count != 0 )
532+ {
533+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
534+ " ' must not have any child" );
535+ }
536+ }
537+ else if (node_type == NodeType::CONDITION)
538+ {
539+ if (children_count != 0 )
540+ {
541+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
542+ " ' must not have any child" );
543+ }
544+ }
573545 }
574546 // recursion
575547 for (auto child = node->FirstChildElement (); child != nullptr ;
0 commit comments