Skip to content

Commit 4d8664b

Browse files
author
Gaël Écorchard
committed
Implement writeTreeDTD()
Signed-off-by: Gaël Écorchard <[email protected]>
1 parent 11e9d1a commit 4d8664b

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

include/behaviortree_cpp/xml_parsing.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ void VerifyXML(const std::string& xml_text,
6060
std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory,
6161
bool include_builtin = false);
6262

63+
/**
64+
* @brief writeTreeDTD generates a DTD for the nodes defined in the factory
65+
*
66+
* @param factory the factory with the registered types
67+
*
68+
* @return string containing the XML.
69+
*/
70+
[[nodiscard]]
71+
std::string writeTreeDTD(const BehaviorTreeFactory& factory);
72+
6373
/**
6474
* @brief WriteTreeToXML create a string that contains the XML that corresponds to a given tree.
6575
* When using this function with a logger, you should probably set both add_metadata and

src/xml_parsing.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
#include <functional>
1414
#include <list>
15+
#include <map>
16+
#include <sstream>
17+
#include <string>
1518

1619
#if defined(__linux) || defined(__linux__)
1720
#pragma GCC diagnostic push
@@ -1117,6 +1120,149 @@ std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory,
11171120
return std::string(printer.CStr(), size_t(printer.CStrSize() - 1));
11181121
}
11191122

1123+
std::string writeTreeDTD(const BehaviorTreeFactory& factory)
1124+
{
1125+
/* Prepare the data. */
1126+
std::map<std::string, const TreeNodeManifest*> ordered_models;
1127+
std::ostringstream models_max_one;
1128+
std::size_t i = 0;
1129+
for (const auto& [registration_id, model] : factory.manifests())
1130+
{
1131+
ordered_models.insert({registration_id, &model});
1132+
models_max_one << registration_id;
1133+
if (i != factory.manifests().size() - 1)
1134+
{
1135+
models_max_one << "|";
1136+
}
1137+
i++;
1138+
}
1139+
1140+
/* For a TreeNodesModel entry. */
1141+
// PortsList ports;
1142+
// std::string description;
1143+
auto tree_nodes_model_dtd = [&models_max_one] (const TreeNodeManifest* manifest) -> std::string {
1144+
std::ostringstream dtd;
1145+
if ((manifest->type == NodeType::CONDITION) or (manifest->type == NodeType::ACTION))
1146+
{
1147+
/* No children. */
1148+
dtd << "<!ELEMENT " << manifest->registration_ID << " EMPTY>\n";
1149+
}
1150+
else if ((manifest->type == NodeType::DECORATOR)
1151+
or (manifest->type == NodeType::SUBTREE))
1152+
{
1153+
/* One child. */
1154+
dtd << "<!ELEMENT " << manifest->registration_ID << " (" << models_max_one.str() << ")>\n";
1155+
}
1156+
else
1157+
{
1158+
/* NodeType::CONTROL. */
1159+
// TODO: check the code, the doc says 1..N but why not 0..N?
1160+
dtd << "<!ELEMENT " << manifest->registration_ID << " (" << models_max_one.str() << ")*>\n";
1161+
}
1162+
dtd << "<!ATTLIST " << manifest->registration_ID << " name CDATA #IMPLIED>\n";
1163+
for (const auto& [port_name, port_info] : manifest->ports)
1164+
{
1165+
std::string type;
1166+
if (port_info.type() == typeid(std::string))
1167+
{
1168+
type = "CDATA";
1169+
}
1170+
else if (port_info.type() == typeid(int))
1171+
{
1172+
type = "CDATA";
1173+
}
1174+
else if (port_info.type() == typeid(double))
1175+
{
1176+
type = "CDATA";
1177+
}
1178+
else if (port_info.type() == typeid(bool))
1179+
{
1180+
type = "(true|false)";
1181+
}
1182+
else
1183+
{
1184+
type = "CDATA";
1185+
}
1186+
std::string attr_def;
1187+
if (port_info.defaultValue().empty())
1188+
{
1189+
attr_def = "#REQUIRED";
1190+
}
1191+
else
1192+
{
1193+
attr_def = "\"" + port_info.defaultValueString() + "\"";
1194+
}
1195+
dtd << "<!ATTLIST " << manifest->registration_ID << " " << port_name << " " << type << " " << attr_def << ">\n";
1196+
}
1197+
return dtd.str();
1198+
};
1199+
1200+
std::ostringstream dtd;
1201+
1202+
dtd << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
1203+
1204+
// dtd << "<!DOCTYPE root [\n";
1205+
dtd << "<!ELEMENT root (BehaviorTree|TreeNodesModel|include)*>\n";
1206+
dtd << "<!ATTLIST root BTCPP_format CDATA #REQUIRED>\n";
1207+
dtd << "<!ATTLIST root main_tree_to_execute CDATA #IMPLIED>\n";
1208+
dtd << "\n";
1209+
1210+
dtd << "<!ELEMENT BehaviorTree (Action|Condition|Control|Decorator|SubTree|" << models_max_one.str() << ")>\n";
1211+
dtd << "<!ATTLIST BehaviorTree ID CDATA #REQUIRED>\n";
1212+
dtd << "\n";
1213+
1214+
dtd << "<!ELEMENT TreeNodesModel (Action|Condition|Control|Decorator|include)*>\n";
1215+
dtd << "\n";
1216+
1217+
dtd << "<!ELEMENT include EMPTY>\n";
1218+
dtd << "<!ATTLIST include path CDATA #REQUIRED>\n";
1219+
dtd << "<!ATTLIST include ros_pkg CDATA #IMPLIED>\n";
1220+
1221+
dtd << "<!ELEMENT Action (input_port*,output_port*,description?)>\n";
1222+
dtd << "<!ATTLIST Action ID CDATA #REQUIRED>\n";
1223+
dtd << "\n";
1224+
1225+
dtd << "<!ELEMENT Condition (input_port*,description?)*>\n";
1226+
dtd << "<!ATTLIST Condition ID CDATA #REQUIRED>\n";
1227+
dtd << "\n";
1228+
1229+
dtd << "<!ELEMENT Control (input_port*,output_port*,description?)*>\n";
1230+
dtd << "<!ATTLIST Control ID CDATA #REQUIRED>\n";
1231+
dtd << "\n";
1232+
1233+
dtd << "<!ELEMENT Decorator (input_port*,output_port*,description?)*>\n";
1234+
dtd << "<!ATTLIST Decorator ID CDATA #REQUIRED>\n";
1235+
dtd << "\n";
1236+
1237+
dtd << "<!ELEMENT SubTree (#PCDATA)>\n";
1238+
dtd << "<!ATTLIST SubTree ID CDATA #REQUIRED>\n";
1239+
dtd << "\n";
1240+
1241+
dtd << "<!ELEMENT description (#PCDATA)>\n";
1242+
dtd << "\n";
1243+
1244+
dtd << "<!ELEMENT input_port (#PCDATA)>\n";
1245+
dtd << "<!ATTLIST input_port name CDATA #REQUIRED\n";
1246+
dtd << " type CDATA #IMPLIED\n";
1247+
dtd << " default CDATA #IMPLIED>\n";
1248+
dtd << "\n";
1249+
1250+
dtd << "<!ELEMENT output_port (#PCDATA)>\n";
1251+
dtd << "<!ATTLIST output_port name CDATA #REQUIRED\n";
1252+
dtd << " type CDATA #REQUIRED>\n";
1253+
dtd << "\n";
1254+
1255+
for (const auto& [registration_id, model] : ordered_models)
1256+
{
1257+
dtd << tree_nodes_model_dtd(model);
1258+
dtd << "\n";
1259+
}
1260+
1261+
// dtd << "]>\n";
1262+
1263+
return dtd.str();
1264+
}
1265+
11201266
Tree buildTreeFromText(const BehaviorTreeFactory& factory, const std::string& text,
11211267
const Blackboard::Ptr& blackboard)
11221268
{

0 commit comments

Comments
 (0)