From 4d8664b50c8ef032e69d1a4e5eeb447f6d759287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20=C3=89corchard?= Date: Mon, 13 Nov 2023 09:23:35 +0100 Subject: [PATCH] Implement writeTreeDTD() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël Écorchard --- include/behaviortree_cpp/xml_parsing.h | 10 ++ src/xml_parsing.cpp | 146 +++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/include/behaviortree_cpp/xml_parsing.h b/include/behaviortree_cpp/xml_parsing.h index 6e8767676..6fb73d58c 100644 --- a/include/behaviortree_cpp/xml_parsing.h +++ b/include/behaviortree_cpp/xml_parsing.h @@ -60,6 +60,16 @@ void VerifyXML(const std::string& xml_text, std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory, bool include_builtin = false); +/** + * @brief writeTreeDTD generates a DTD for the nodes defined in the factory + * + * @param factory the factory with the registered types + * + * @return string containing the XML. + */ +[[nodiscard]] +std::string writeTreeDTD(const BehaviorTreeFactory& factory); + /** * @brief WriteTreeToXML create a string that contains the XML that corresponds to a given tree. * When using this function with a logger, you should probably set both add_metadata and diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index a24fe31fe..00ff4ff2b 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #if defined(__linux) || defined(__linux__) #pragma GCC diagnostic push @@ -1117,6 +1120,149 @@ std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory, return std::string(printer.CStr(), size_t(printer.CStrSize() - 1)); } +std::string writeTreeDTD(const BehaviorTreeFactory& factory) +{ + /* Prepare the data. */ + std::map ordered_models; + std::ostringstream models_max_one; + std::size_t i = 0; + for (const auto& [registration_id, model] : factory.manifests()) + { + ordered_models.insert({registration_id, &model}); + models_max_one << registration_id; + if (i != factory.manifests().size() - 1) + { + models_max_one << "|"; + } + i++; + } + + /* For a TreeNodesModel entry. */ + // PortsList ports; + // std::string description; + auto tree_nodes_model_dtd = [&models_max_one] (const TreeNodeManifest* manifest) -> std::string { + std::ostringstream dtd; + if ((manifest->type == NodeType::CONDITION) or (manifest->type == NodeType::ACTION)) + { + /* No children. */ + dtd << "registration_ID << " EMPTY>\n"; + } + else if ((manifest->type == NodeType::DECORATOR) + or (manifest->type == NodeType::SUBTREE)) + { + /* One child. */ + dtd << "registration_ID << " (" << models_max_one.str() << ")>\n"; + } + else + { + /* NodeType::CONTROL. */ + // TODO: check the code, the doc says 1..N but why not 0..N? + dtd << "registration_ID << " (" << models_max_one.str() << ")*>\n"; + } + dtd << "registration_ID << " name CDATA #IMPLIED>\n"; + for (const auto& [port_name, port_info] : manifest->ports) + { + std::string type; + if (port_info.type() == typeid(std::string)) + { + type = "CDATA"; + } + else if (port_info.type() == typeid(int)) + { + type = "CDATA"; + } + else if (port_info.type() == typeid(double)) + { + type = "CDATA"; + } + else if (port_info.type() == typeid(bool)) + { + type = "(true|false)"; + } + else + { + type = "CDATA"; + } + std::string attr_def; + if (port_info.defaultValue().empty()) + { + attr_def = "#REQUIRED"; + } + else + { + attr_def = "\"" + port_info.defaultValueString() + "\""; + } + dtd << "registration_ID << " " << port_name << " " << type << " " << attr_def << ">\n"; + } + return dtd.str(); + }; + + std::ostringstream dtd; + + dtd << "\n"; + + // dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + dtd << "\n"; + dtd << "\n"; + dtd << "\n"; + + for (const auto& [registration_id, model] : ordered_models) + { + dtd << tree_nodes_model_dtd(model); + dtd << "\n"; + } + + // dtd << "]>\n"; + + return dtd.str(); +} + Tree buildTreeFromText(const BehaviorTreeFactory& factory, const std::string& text, const Blackboard::Ptr& blackboard) {