Skip to content

Commit a9d6e56

Browse files
feat: write the library version as BTCPP_version in the <root> of generated XML (#1264)
writeTreeNodesModelXML() and WriteTreeToXML() now add BTCPP_version="<major>.<minor>" to <root>, next to BTCPP_format. It tells tools like Groot2 which builtin node models and attributes (e.g. the _onlyIf/_onStart preconditions of 4.11) are available. The XSD declares it as an optional attribute. The parser ignores it, as all BT.CPP 4.x releases already ignore unknown <root> attributes, so files written by 4.11 still load in older versions. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1a21a78 commit a9d6e56

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎src/xml_parsing.cpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,14 @@ void addTreeToXML(const Tree& tree, XMLDocument& doc, XMLElement* rootXML,
14541454
addNodeModelToXML(*model, doc, model_root);
14551455
}
14561456
}
1457+
1458+
// "major.minor" of this library, written in the [BTCPP_version] attribute of <root>.
1459+
// It is informative only (e.g. for Groot2): the parser ignores it.
1460+
std::string libraryMajorMinorVersion()
1461+
{
1462+
const std::string version = LibraryVersionString();
1463+
return version.substr(0, version.rfind('.'));
1464+
}
14571465
} // namespace
14581466

14591467
std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory,
@@ -1463,6 +1471,7 @@ std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory,
14631471

14641472
XMLElement* rootXML = doc.NewElement("root");
14651473
rootXML->SetAttribute("BTCPP_format", "4");
1474+
rootXML->SetAttribute("BTCPP_version", libraryMajorMinorVersion().c_str());
14661475
doc.InsertFirstChild(rootXML);
14671476

14681477
XMLElement* model_root = doc.NewElement("TreeNodesModel");
@@ -1641,6 +1650,7 @@ std::string writeTreeXSD(const BehaviorTreeFactory& factory)
16411650
</xs:sequence>
16421651
<xs:attribute name="BTCPP_format" type="xs:string" use="required"/>
16431652
<xs:attribute name="main_tree_to_execute" type="xs:string" use="optional"/>
1653+
<xs:attribute name="BTCPP_version" type="xs:string" use="optional"/>
16441654
</xs:complexType>
16451655
</xs:element>
16461656
)";
@@ -1765,6 +1775,7 @@ std::string WriteTreeToXML(const Tree& tree, bool add_metadata, bool add_builtin
17651775

17661776
XMLElement* rootXML = doc.NewElement("root");
17671777
rootXML->SetAttribute("BTCPP_format", 4);
1778+
rootXML->SetAttribute("BTCPP_version", libraryMajorMinorVersion().c_str());
17681779
doc.InsertFirstChild(rootXML);
17691780

17701781
addTreeToXML(tree, doc, rootXML, add_metadata, add_builtin_models);

‎tests/gtest_factory.cpp‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,30 @@ TEST(BehaviorTreeFactory, ManifestMethod)
481481
EXPECT_NE(xml.find(expectedXML), std::string::npos);
482482
}
483483

484+
TEST(BehaviorTreeFactory, WrittenXMLHasLibraryVersion)
485+
{
486+
// "4.11.2" -> "4.11"
487+
const std::string version = LibraryVersionString();
488+
const std::string major_minor = version.substr(0, version.rfind('.'));
489+
const std::string expected = "BTCPP_version=\"" + major_minor + "\"";
490+
491+
BehaviorTreeFactory factory;
492+
EXPECT_NE(writeTreeNodesModelXML(factory).find(expected), std::string::npos);
493+
494+
auto tree = factory.createTreeFromText(R"(
495+
<root BTCPP_format="4">
496+
<BehaviorTree ID="MainTree">
497+
<AlwaysSuccess/>
498+
</BehaviorTree>
499+
</root>)");
500+
const auto xml = WriteTreeToXML(tree, false, false);
501+
EXPECT_NE(xml.find(expected), std::string::npos);
502+
503+
// the attribute is ignored by the parser
504+
auto reloaded = factory.createTreeFromText(xml);
505+
EXPECT_EQ(reloaded.tickWhileRunning(), NodeStatus::SUCCESS);
506+
}
507+
484508
TEST(BehaviorTreeFactory, ReturnByValue)
485509
{
486510
// Issue #937: BehaviorTreeFactory cannot be returned by value from

0 commit comments

Comments
 (0)