@@ -429,125 +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 (ID.empty ())
435- {
436- ThrowError (line_number, " The tag <Decorator> must have the "
437- " attribute [ID]" );
438- }
439- if (children_count != 1 )
440- {
441- ThrowError (line_number, " The tag <Decorator> with ID '" + ID +
442- " ' must have exactly 1 "
443- " child" );
444- }
445- }
446- else if (name == " Action" )
447- {
448- if (ID.empty ())
449- {
450- ThrowError (line_number, " The tag <Action> must have the "
451- " attribute [ID]" );
452- }
453- if (children_count != 0 )
454- {
455- ThrowError (line_number, " The tag <Action> with ID '" + ID +
456- " ' must not have any "
457- " child" );
458- }
438+ ThrowError (line_number,
439+ std::string (" The tag <" ) + name + " > must have the attribute [ID]" );
459440 }
460- else if (name == " Condition" )
441+
442+ if (name == " BehaviorTree" )
461443 {
462- if (ID.empty ())
463- {
464- ThrowError (line_number, " The tag <Condition> must have the "
465- " attribute [ID]" );
466- }
467- if (children_count != 0 )
444+ if (ID.empty () && behavior_tree_count > 1 )
468445 {
469- ThrowError (line_number, " The tag <Condition> with ID '" + ID +
470- " ' must not have any "
471- " child" );
446+ ThrowError (line_number, " The tag <BehaviorTree> must have the attribute [ID]" );
472447 }
473- }
474- else if (name == " Control" )
475- {
476- if (ID.empty ())
448+ if (registered_nodes.count (ID) != 0 )
477449 {
478- ThrowError (line_number, " The tag <Control > must have the "
479- " attribute [ID] " );
450+ ThrowError (line_number, " The attribute [ID] of tag <BehaviorTree > must not use "
451+ " the name of a registered Node " );
480452 }
481- if (children_count == 0 )
453+ if (children_count != 1 )
482454 {
483- ThrowError (line_number, " The tag <Control> with ID '" + ID +
484- " ' must have at least 1 "
485- " child" );
455+ ThrowError (line_number, " The tag <BehaviorTree> with ID '" + ID +
456+ " ' must have exactly 1 child" );
486457 }
487458 }
488459 else if (name == " SubTree" )
489460 {
490- if (ID.empty ())
491- {
492- ThrowError (line_number, " The tag <SubTree> must have the "
493- " attribute [ID]" );
494- }
495461 if (children_count != 0 )
496462 {
497463 ThrowError (line_number,
498464 " <SubTree> with ID '" + ID + " ' should not have any child" );
499465 }
500466 if (registered_nodes.count (ID) != 0 )
501467 {
502- ThrowError (line_number, " The attribute [ID] of tag <SubTree> must "
503- " not use the name of a registered Node" );
504- }
505- }
506- else if (name == " BehaviorTree" )
507- {
508- if (ID.empty () && behavior_tree_count > 1 )
509- {
510- ThrowError (line_number, " The tag <BehaviorTree> must have the "
511- " attribute [ID]" );
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" );
517- }
518- if (children_count != 1 )
519- {
520- ThrowError (line_number, " The tag <BehaviorTree> with ID '" + ID +
521- " ' must have exactly 1 "
522- " child" );
468+ ThrowError (line_number, " The attribute [ID] of tag <SubTree> must not use the "
469+ " name of a registered Node" );
523470 }
524471 }
525472 else
526473 {
527- // search in the factory and the list of subtrees
528- 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);
529476 bool found = (search != registered_nodes.end ());
530477 if (!found)
531478 {
532479 ThrowError (line_number, std::string (" Node not recognized: " ) + name);
533480 }
534481
535- 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)
536486 {
537487 if (children_count != 1 )
538488 {
539- ThrowError (line_number, std::string (" The node < " ) + name + " > with ID ' " + ID +
489+ ThrowError (line_number, std::string (" The node ' " ) + registered_name +
540490 " ' must have exactly 1 child" );
541491 }
542492 }
543- else if (search-> second == NodeType::CONTROL)
493+ else if (node_type == NodeType::CONTROL)
544494 {
545495 if (children_count == 0 )
546496 {
547- ThrowError (line_number, std::string (" The node < " ) + name + " > with ID ' " + ID +
497+ ThrowError (line_number, std::string (" The node ' " ) + registered_name +
548498 " ' must have 1 or more children" );
549499 }
550- if (name == " ReactiveSequence" )
500+ if (registered_name == " ReactiveSequence" )
551501 {
552502 size_t async_count = 0 ;
553503 for (auto child = node->FirstChildElement (); child != nullptr ;
@@ -569,14 +519,29 @@ void VerifyXML(const std::string& xml_text,
569519 ++async_count;
570520 if (async_count > 1 )
571521 {
572- ThrowError (line_number, std::string (" A ReactiveSequence with ID '" + ID +
573- " ' cannot have more "
574- " than one async child." ));
522+ ThrowError (line_number, std::string (" A ReactiveSequence cannot have "
523+ " more than one async child." ));
575524 }
576525 }
577526 }
578527 }
579528 }
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+ }
580545 }
581546 // recursion
582547 for (auto child = node->FirstChildElement (); child != nullptr ;
0 commit comments