@@ -429,153 +429,120 @@ void VerifyXML(const std::string& xml_text,
429
429
const std::string ID = node->Attribute (" ID" ) ? node->Attribute (" ID" ) : " " ;
430
430
const int line_number = node->GetLineNum ();
431
431
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 ())
433
437
{
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
- }
438
+ ThrowError (line_number,
439
+ std::string (" The tag <" ) + name + " > must have the attribute [ID]" );
445
440
}
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
- }
459
- }
460
- else if (name == " Condition" )
441
+
442
+ if (name == " BehaviorTree" )
461
443
{
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 )
468
445
{
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]" );
472
447
}
473
- }
474
- else if (name == " Control" )
475
- {
476
- if (ID.empty ())
448
+ if (registered_nodes.count (ID) != 0 )
477
449
{
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 " );
480
452
}
481
- if (children_count == 0 )
453
+ if (children_count != 1 )
482
454
{
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" );
486
457
}
487
458
}
488
459
else if (name == " SubTree" )
489
460
{
490
- if (ID.empty ())
491
- {
492
- ThrowError (line_number, " The tag <SubTree> must have the "
493
- " attribute [ID]" );
494
- }
495
461
if (children_count != 0 )
496
462
{
497
463
ThrowError (line_number,
498
464
" <SubTree> with ID '" + ID + " ' should not have any child" );
499
465
}
500
466
if (registered_nodes.count (ID) != 0 )
501
467
{
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" );
523
470
}
524
471
}
525
472
else
526
473
{
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);
529
476
bool found = (search != registered_nodes.end ());
530
477
if (!found)
531
478
{
532
479
ThrowError (line_number, std::string (" Node not recognized: " ) + name);
533
480
}
534
-
535
- if (search->second == NodeType::DECORATOR)
536
- {
537
- if (children_count != 1 )
538
- {
539
- ThrowError (line_number, std::string (" The node <" ) + name + " > with ID '" + ID +
540
- " ' must have exactly 1 child" );
541
- }
542
- }
543
- else if (search->second == NodeType::CONTROL)
481
+ else
544
482
{
545
- if (children_count == 0 )
483
+ const auto node_type = search->second ;
484
+ const std::string& registered_name = search->first ;
485
+
486
+ if (node_type == NodeType::DECORATOR)
546
487
{
547
- ThrowError (line_number, std::string (" The node <" ) + name + " > with ID '" + ID +
548
- " ' must have 1 or more children" );
488
+ if (children_count != 1 )
489
+ {
490
+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
491
+ " ' must have exactly 1 child" );
492
+ }
549
493
}
550
- if (name == " ReactiveSequence " )
494
+ else if (node_type == NodeType::CONTROL )
551
495
{
552
- size_t async_count = 0 ;
553
- for (auto child = node->FirstChildElement (); child != nullptr ;
554
- child = child->NextSiblingElement ())
496
+ if (children_count == 0 )
555
497
{
556
- const std::string child_name = child->Name ();
557
- const auto child_search = registered_nodes.find (child_name);
558
- if (child_search == registered_nodes.end ())
559
- {
560
- ThrowError (child->GetLineNum (),
561
- std::string (" Unknown node type: " ) + child_name);
562
- }
563
- const auto child_type = child_search->second ;
564
- if (child_type == NodeType::CONTROL &&
565
- ((child_name == " ThreadedAction" ) ||
566
- (child_name == " StatefulActionNode" ) ||
567
- (child_name == " CoroActionNode" ) || (child_name == " AsyncSequence" )))
498
+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
499
+ " ' must have 1 or more children" );
500
+ }
501
+ if (registered_name == " ReactiveSequence" )
502
+ {
503
+ size_t async_count = 0 ;
504
+ for (auto child = node->FirstChildElement (); child != nullptr ;
505
+ child = child->NextSiblingElement ())
568
506
{
569
- ++async_count;
570
- if (async_count > 1 )
507
+ const std::string child_name = child->Name ();
508
+ const auto child_search = registered_nodes.find (child_name);
509
+ if (child_search == registered_nodes.end ())
571
510
{
572
- ThrowError (line_number, std::string (" A ReactiveSequence with ID '" + ID +
573
- " ' cannot have more "
574
- " than one async child." ));
511
+ ThrowError (child->GetLineNum (),
512
+ std::string (" Unknown node type: " ) + child_name);
513
+ }
514
+ const auto child_type = child_search->second ;
515
+ if (child_type == NodeType::CONTROL &&
516
+ ((child_name == " ThreadedAction" ) ||
517
+ (child_name == " StatefulActionNode" ) ||
518
+ (child_name == " CoroActionNode" ) || (child_name == " AsyncSequence" )))
519
+ {
520
+ ++async_count;
521
+ if (async_count > 1 )
522
+ {
523
+ ThrowError (line_number, std::string (" A ReactiveSequence cannot have "
524
+ " more than one async child." ));
525
+ }
575
526
}
576
527
}
577
528
}
578
529
}
530
+ else if (node_type == NodeType::ACTION)
531
+ {
532
+ if (children_count != 0 )
533
+ {
534
+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
535
+ " ' must not have any child" );
536
+ }
537
+ }
538
+ else if (node_type == NodeType::CONDITION)
539
+ {
540
+ if (children_count != 0 )
541
+ {
542
+ ThrowError (line_number, std::string (" The node '" ) + registered_name +
543
+ " ' must not have any child" );
544
+ }
545
+ }
579
546
}
580
547
}
581
548
// recursion
0 commit comments