8#include <rclcpp/rclcpp.hpp>
10#include <capabilities2_events/event_parameters.hpp>
34 auto* decl =
system_doc.NewDeclaration(R
"(xml version="1.0" encoding="UTF-8")");
46 tinyxml2::XMLError xml_status =
default_document.LoadFile(file_path.c_str());
49 if (xml_status != tinyxml2::XMLError::XML_SUCCESS)
51 RCLCPP_ERROR(
node_->get_logger(),
"[xml_parser] Error loading plan: %s, Error: %s", file_path.c_str(),
default_document.ErrorName());
55 RCLCPP_INFO(
node_->get_logger(),
"Plan loaded from : %s", file_path.c_str());
71 tinyxml2::XMLDocument documentChecking;
74 tinyxml2::XMLError xml_status = documentChecking.Parse(plan.
plan.c_str());
77 if (xml_status != tinyxml2::XMLError::XML_SUCCESS)
79 RCLCPP_ERROR(
node_->get_logger(),
"Parsing the plan from service request message failed with error: %s", documentChecking.ErrorName());
94 RCLCPP_INFO(
node_->get_logger(),
"Plan being parsed: \n\n %s", plan.
plan.c_str());
100 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Adding completion runner to the plan");
104 std::string modified_plan;
106 RCLCPP_DEBUG(
node_->get_logger(),
"[xml_parser] Plan after adding closing event :\n\n %s", modified_plan.c_str());
108 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Completion runner added. Extracting the plan element.");
113 if (
plan_ ==
nullptr)
116 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] <Plan> element extracted successfully.");
119 std::string error_msg;
120 std::vector<std::string>
control_list = {
"sequential",
"parallel_any",
"parallel_all",
"recovery" };
128 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Plan syntax validation successful");
133 RCLCPP_INFO(
node_->get_logger(),
"Finished parsing the plan");
146 tinyxml2::XMLPrinter printer;
147 document_xml.Print(&printer);
148 document_string = printer.CStr();
159 bool search(std::vector<std::string> list, std::string value)
161 return (std::find(list.begin(), list.end(), value) != list.end());
175 std::string plan_tag(document.FirstChildElement()->Name());
177 if (plan_tag ==
"Plan")
178 return document.FirstChildElement(
"Plan")->FirstChildElement();
195 tinyxml2::XMLPrinter printer;
196 element->Accept(&printer);
197 parameters = printer.CStr();
218 bool check_syntax(tinyxml2::XMLElement* element, std::vector<std::string>&
control_list, std::vector<std::string>& rejected, std::string& error)
220 const char* type =
nullptr;
221 const char*
interface = nullptr;
222 const char* provider =
nullptr;
224 std::string elementTag(element->Name());
226 std::string parameter_string;
229 bool returnValue =
true;
231 std::string typetag =
"";
232 std::string interfacetag =
"";
233 std::string providertag =
"";
235 bool hasChildren = !element->NoChildren();
236 bool hasSiblings = (element->NextSiblingElement() !=
nullptr);
238 if (elementTag ==
"Control")
240 element->QueryStringAttribute(
"type", &type);
248 error =
"Control tag '" + typetag +
"' not available in the valid list";
249 rejected.push_back(parameter_string);
255 error =
"Control tag missing 'type' attribute: " + parameter_string;
256 rejected.push_back(parameter_string);
266 else if (elementTag ==
"Runner")
268 element->QueryStringAttribute(
"interface", &interface);
269 element->QueryStringAttribute(
"provider", &provider);
273 error =
"Runner tag missing 'interface' attribute: " + parameter_string;
274 rejected.push_back(parameter_string);
280 error =
"Runner tag missing 'provider' attribute: " + parameter_string;
281 rejected.push_back(parameter_string);
290 error =
"XML element is not valid :" + parameter_string;
291 rejected.push_back(parameter_string);
309 tinyxml2::XMLElement* plan = document.FirstChildElement(
"Plan");
312 tinyxml2::XMLElement* outerControl = document.NewElement(
"Control");
313 outerControl->SetAttribute(
"type",
"sequential");
314 outerControl->SetAttribute(
"name",
"fabric_completion_control");
317 while (tinyxml2::XMLNode* child = plan->FirstChild())
318 outerControl->InsertEndChild(child);
321 plan->InsertEndChild(outerControl);
324 tinyxml2::XMLElement* newRunner = document.NewElement(
"Runner");
325 newRunner->SetAttribute(
"interface",
"fabric_capabilities/FabricCompletionRunner");
326 newRunner->SetAttribute(
"provider",
"fabric_capabilities/FabricCompletionRunner");
327 newRunner->SetAttribute(
"plan_id", plan_id.c_str());
328 outerControl->InsertEndChild(newRunner);
330 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] CompletionRunner added to the plan");
353 node.source.
interface =
"capabilities2_runner/InputMultiplexRunner";
354 node.source.
provider =
"capabilities2_runner/InputMultiplexRunner";
356 node.source.
parameters.set_value(
"input_count", input_count, capabilities2_events::OptionType::INT);
359 plan.
connections[connection_id].description = description;
369 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] ParallelAll connection added to the plan with %d inputs, id %d", input_count, connection_id);
372 return connection_id;
391 node.source.
interface =
"capabilities2_runner/InputMultiplexRunner";
392 node.source.
provider =
"capabilities2_runner/InputMultiplexRunner";
394 node.source.
parameters.set_value(
"input_count", input_count, capabilities2_events::OptionType::INT);
397 plan.
connections[connection_id].description = description;
407 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] ParallelAny connection added to the plan with id %d", connection_id);
410 return connection_id;
451 capabilities2_events::EventParameters parameters;
454 const tinyxml2::XMLAttribute* attr = element->FirstAttribute();
459 std::string key = attr->Name();
460 std::string string_value = attr->Value();
463 if (key ==
"interface")
470 if (key ==
"provider")
477 if (string_value ==
"true" || string_value ==
"false")
479 const bool bool_value = (string_value ==
"true");
480 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Extracted attribute: %s = %s (bool)", key.c_str(), bool_value ?
"true" :
"false");
481 parameters.set_value(key, bool_value, capabilities2_events::OptionType::BOOL);
486 char* int_end =
nullptr;
488 const long int_value_long = std::strtol(string_value.c_str(), &int_end, 10);
490 if (int_end !=
nullptr && *int_end ==
'\0' && errno == 0)
492 const int int_value =
static_cast<int>(int_value_long);
493 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Extracted attribute: %s = %d (int)", key.c_str(), int_value);
494 parameters.set_value(key, int_value, capabilities2_events::OptionType::INT);
498 char* double_end =
nullptr;
500 const double double_value = std::strtod(string_value.c_str(), &double_end);
502 if (double_end !=
nullptr && *double_end ==
'\0' && errno == 0)
504 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Extracted attribute: %s = %f (double)", key.c_str(), double_value);
505 parameters.set_value(key, double_value, capabilities2_events::OptionType::DOUBLE);
509 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Extracted attribute: %s = %s (string)", key.c_str(), string_value.c_str());
510 parameters.set_value(key, string_value, capabilities2_events::OptionType::STRING);
531 int last_conn_id = connection_id;
533 const char* type =
nullptr;
534 const char* name =
nullptr;
535 const char*
interface = nullptr;
536 const char* provider =
nullptr;
538 std::string elementTag(element->Name());
540 std::string typetag =
"";
541 std::string description =
"";
542 std::string interfacetag =
"";
543 std::string providertag =
"";
545 bool hasChildren = (element->FirstChildElement() !=
nullptr);
546 bool hasSiblings = (element->NextSiblingElement() !=
nullptr);
548 if (elementTag ==
"Control")
550 type = element->Attribute(
"type");
551 name = element->Attribute(
"name");
559 if (typetag ==
"sequential")
564 else if (typetag ==
"parallel_any")
572 last_conn_id =
add_parallel_any(plan, last_conn_id + 1,
"parallel_any_for_muxing_outputs");
575 else if (typetag ==
"parallel_all")
583 last_conn_id =
add_parallel_all(plan, last_conn_id + 1,
"parallel_all_for_muxing_outputs");
586 else if (typetag ==
"recovery")
594 last_conn_id =
add_parallel_any(plan, last_conn_id + 1,
"parallel_any_for_muxing_recovery");
601 last_conn_id =
extract_connections(element->NextSiblingElement(), plan, last_conn_id + 1, connection_type, conn_description);
606 else if (elementTag ==
"Runner")
608 interface = element->Attribute(
"interface");
609 provider = element->Attribute(
"provider");
612 interfacetag = interface;
615 providertag = provider;
617 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] Creating fabric connection: interface = %s, provider = %s", interfacetag.c_str(),
618 providertag.c_str());
627 predecessor_id = connection_id - 1;
630 plan.
connections[connection_id].description = conn_description;
634 if (connection_id != 0)
644 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] set on_success for id %d to interface %s", predecessor_id,
645 plan.
connections[predecessor_id].on_success.interface.c_str());
651 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] set on_start for id %d to interface %s", predecessor_id,
652 plan.
connections[predecessor_id].on_start.interface.c_str());
658 RCLCPP_INFO(
node_->get_logger(),
"[xml_parser] set on_failure for id %d to interface %s", predecessor_id,
659 plan.
connections[predecessor_id].on_failure.interface.c_str());
664 last_conn_id = this->
extract_connections(element->NextSiblingElement(), plan, connection_id + 1, connection_type);
666 last_conn_id = connection_id;
693 tinyxml2::XMLElement*
plan_ =
nullptr;
Abstract base class for XML plan parsing plugins.
Definition parser_base.hpp:18
void initialize_base(const rclcpp::Node::SharedPtr &node, const std::string &plugin_name)
Base initialization method for derived classes.
Definition parser_base.hpp:64
rclcpp::Node::SharedPtr node_
Shared pointer to the ROS2 node.
Definition parser_base.hpp:73
Syntax validation plugin for XML plans.
Definition xml_parser_plugin.hpp:20
tinyxml2::XMLDocument current_document_
XML Document to hold the current plan.
Definition xml_parser_plugin.hpp:703
std::vector< std::string > control_list
List of valid control tags.
Definition xml_parser_plugin.hpp:678
bool load_file(const std::string &file_path, fabric::Plan &plan) override
load a file into an XML document
Definition xml_parser_plugin.hpp:44
int add_parallel_all(fabric::Plan &plan, int connection_id=0, std::string description="")
Adds a system connection for parallel input multiplexing with waiting for all inputs.
Definition xml_parser_plugin.hpp:341
bool search(std::vector< std::string > list, std::string value)
search a string in a vector of strings
Definition xml_parser_plugin.hpp:159
void parse(fabric::Plan &plan) override
Parse the given XML plan.
Definition xml_parser_plugin.hpp:92
tinyxml2::XMLElement * plan_
Pointer to the plan element in the XML document.
Definition xml_parser_plugin.hpp:693
tinyxml2::XMLElement * extract_plan(tinyxml2::XMLDocument &document)
Extract the <Plan> element from the XML document.
Definition xml_parser_plugin.hpp:173
bool check_compatibility(const fabric::Plan &plan) override
Check the compatibility of the given plan with the given parser.
Definition xml_parser_plugin.hpp:68
tinyxml2::XMLDocument system_doc
XML Document for system runners.
Definition xml_parser_plugin.hpp:683
int runner_index
Index for assigning unique IDs to system runners.
Definition xml_parser_plugin.hpp:688
int add_parallel_any(fabric::Plan &plan, int connection_id=0, std::string description="")
Adds a system connection for parallel input multiplexing with waiting for any inputs.
Definition xml_parser_plugin.hpp:383
tinyxml2::XMLDocument default_document
Default XML document for loading from file.
Definition xml_parser_plugin.hpp:698
virtual ~XMLParser()=default
void add_completion_runner(tinyxml2::XMLDocument &document, const std::string &plan_id)
add a completion runner to the plan This function adds a new <Control> element with type "sequential"...
Definition xml_parser_plugin.hpp:306
void convert_to_string(tinyxml2::XMLDocument &document_xml, std::string &document_string)
convert XMLDocument to std::string
Definition xml_parser_plugin.hpp:144
bool convert_to_string(tinyxml2::XMLElement *element, std::string ¶meters)
convert XMLElement to std::string
Definition xml_parser_plugin.hpp:191
void initialize(const rclcpp::Node::SharedPtr &node) override
Initialize the XML parser plugin.
Definition xml_parser_plugin.hpp:30
int extract_connections(tinyxml2::XMLElement *element, fabric::Plan &plan, int connection_id=0, fabric::event connection_type=fabric::event::ON_SUCCESS, std::string conn_description="")
parse through the plan and extract the connections
Definition xml_parser_plugin.hpp:527
capabilities2_events::EventParameters convert_xml_to_event_parameters(tinyxml2::XMLElement *element)
Check and update the system runner id for the successor based on the predecessor's id.
Definition xml_parser_plugin.hpp:449
bool check_syntax(tinyxml2::XMLElement *element, std::vector< std::string > &control_list, std::vector< std::string > &rejected, std::string &error)
check the plan to make sure all control and runner XML elements are valid with minimal required attri...
Definition xml_parser_plugin.hpp:218
Definition parser_base.hpp:9
event
Enumeration for different event types in connections.
Definition structs.hpp:15
@ ON_START
Definition structs.hpp:16
@ ON_FAILURE
Definition structs.hpp:18
@ ON_SUCCESS
Definition structs.hpp:17
Definition structs.hpp:70
std::vector< std::string > rejected_list
Definition structs.hpp:75
std::map< int, connection > connections
Definition structs.hpp:74
std::string plan
Definition structs.hpp:72
std::string plan_id
Definition structs.hpp:71
Structure representing connections between nodes.
Definition structs.hpp:42
node on_success
Definition structs.hpp:46
node source
Definition structs.hpp:43
Base class for driver exceptions.
Definition exception.hpp:14
Structure representing a node in the fabric.
Definition structs.hpp:26
std::string provider
Definition structs.hpp:28
std::string interface
Definition structs.hpp:27
capabilities2_events::EventParameters parameters
Definition structs.hpp:29
int instance_id
Definition structs.hpp:30