YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
XMLReaderFileV3.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
14
15#include <yarp/os/LogStream.h>
16#include <yarp/os/Network.h>
17#include <yarp/os/Property.h>
18
19#include <algorithm>
20#include <iterator>
21#include <sstream>
22#include <string>
23#include <tinyxml.h>
24#include <vector>
25#include <set>
26
27#define SYNTAX_ERROR(line) yError() << "Syntax error while loading" << curr_filename << "at line" << line << "."
28#define SYNTAX_WARNING(line) yWarning() << "Invalid syntax while loading" << curr_filename << "at line" << line << "."
29
30// BUG in TinyXML, see
31// https://sourceforge.net/tracker/?func=detail&aid=3567726&group_id=13559&atid=113559
32// When this bug is fixed upstream we can enable this
33#define TINYXML_UNSIGNED_INT_BUG 0
34
36{
37public:
39 virtual ~Private();
40
44
48
54
58
59 bool CheckIfIncludeSectionIsEnabled(const std::string& href_enable_tags, const std::string& href_disable_tags);
60 bool PerformInclusions(TiXmlNode* pParent, const std::string& parent_fileName, const std::string& current_path);
61 void ReplaceAllStrings(std::string& str, const std::string& from, const std::string& to);
63
64#ifdef USE_DTD
66#endif
67
70 std::string curr_filename;
71 unsigned int minorVersion;
72 unsigned int majorVersion;
75 std::set<std::string> m_enable_set_found_in_all_xml;
76 std::set<std::string> m_disable_set_found_in_all_xml;
77};
78
79
81 parent(p),
82 minorVersion(0),
83 majorVersion(0)
84{
85 verbose_output = false;
86}
87
89
91{
92 yDebug() << "Reading file" << fileName.c_str();
93 auto* doc = new TiXmlDocument(fileName.c_str());
94 if (!doc->LoadFile()) {
95 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
97 }
98
99 if (!doc->RootElement()) {
100 SYNTAX_ERROR(doc->Row()) << "No root element.";
102 }
103
104#ifdef USE_DTD
105 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
106 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
107 if (dtd.parse(childNode->ToUnknown(), curr_filename)) {
108 break;
109 }
110 }
111 }
112
113 if (!dtd.valid()) {
114 SYNTAX_WARNING(doc->Row()) << "No DTD found. Assuming version yarprobotinterfaceV1.0";
115 dtd.setDefault();
117 }
118
119 if (dtd.type != RobotInterfaceDTD::DocTypeRobot) {
120 SYNTAX_WARNING(doc->Row()) << "Expected document of type" << DocTypeToString(RobotInterfaceDTD::DocTypeRobot)
121 << ". Found" << DocTypeToString(dtd.type);
122 }
123
124 if (dtd.majorVersion != 1 || dtd.minorVersion != 0) {
125 SYNTAX_WARNING(doc->Row()) << "Only yarprobotinterface DTD version 1.0 is supported";
126 }
127#endif
128
129 std::string current_path;
130 current_path = fileName.substr(0, fileName.find_last_of("\\/"));
131 std::string current_filename;
132 std::string log_filename;
133 current_filename = fileName.substr(fileName.find_last_of("\\/") + 1);
134 log_filename = current_filename.substr(0, current_filename.find(".xml"));
135 log_filename += "_preprocessor_log.xml";
136
137 std::string enable_tags_string;
138 yarp::os::Bottle* be = config.find("enable_tags").asList();
139 if (be) { enable_tags_string = be->toString();}
140
141 std::string disable_tags_string;
142 yarp::os::Bottle* bd = config.find("disable_tags").asList();
143 if (bd) { disable_tags_string = bd->toString();}
144
145 {
146 char* all_string = strdup(enable_tags_string.c_str());
147 if (all_string==nullptr) { yError() << "Internal error"; return yarp::robotinterface::XMLReaderResult::ParsingFailed(); }
148 char* token = strtok(all_string, " ");
149 while (token) {
150 m_enabled_options_from_command_line.insert(token);
151 token = strtok(NULL, " ");
152 }
153 free (all_string);
154 }
155 {
156 char* all_string = strdup(disable_tags_string.c_str());
157 if (all_string == nullptr) { yError() << "Internal error"; return yarp::robotinterface::XMLReaderResult::ParsingFailed(); }
158 char* token = strtok(all_string, " ");
159 while (token) {
160 m_disabled_options_from_command_line.insert(token);
161 token = strtok(NULL, " ");
162 }
163 free(all_string);
164 }
165 yInfo() << "Yarprobotinterface was started using the following enable_tags:"<< enable_tags_string;
166 yInfo() << "Yarprobotinterface was started using the following disable_tags:" << disable_tags_string;
167
168 double start_time = yarp::os::Time::now();
169 PerformInclusions(doc->RootElement(), current_filename, current_path);
170 double end_time = yarp::os::Time::now();
171
172 std::string all_enable_att_string = "List of all enable attributes found in the include tags: ";
173 for (auto it = m_enable_set_found_in_all_xml.begin(); it != m_enable_set_found_in_all_xml.end(); it++)
174 {
175 all_enable_att_string += (" " + *it);
176 }
177 yDebug() << all_enable_att_string;
178
179 std::string all_disable_att_string = "List of all disable attributes found in the include tags: ";
180 for (auto it = m_disable_set_found_in_all_xml.begin(); it != m_disable_set_found_in_all_xml.end(); it++)
181 {
182 all_disable_att_string += (" " + *it);
183 }
184 yDebug() << all_disable_att_string;
185
186 std::string full_log_withpath = current_path + std::string("\\") + log_filename;
187 std::replace(full_log_withpath.begin(), full_log_withpath.end(), '\\', '/');
188 yDebug() << "Preprocessor complete in: " << end_time - start_time << "s";
189 if (verbose_output)
190 {
191 yDebug() << "Preprocessor output stored in: " << full_log_withpath;
192 doc->SaveFile(full_log_withpath);
193 }
194
195 yarp::robotinterface::XMLReaderResult result = readRobotTag(doc->RootElement());
196 delete doc;
197
198 // yDebug() << robot;
199
200 return result;
201}
202
204{
205 curr_filename = " XML runtime string ";
206 auto* doc = new TiXmlDocument();
207 if (!doc->Parse(xmlString.c_str())) {
208 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
210 }
211
212 if (!doc->RootElement()) {
213 SYNTAX_ERROR(doc->Row()) << "No root element.";
215 }
216
217 yarp::robotinterface::XMLReaderResult result = readRobotTag(doc->RootElement());
218 delete doc;
219
220 return result;
221}
222
223bool yarp::robotinterface::impl::XMLReaderFileV3::Private::CheckIfIncludeSectionIsEnabled(const std::string& hrefxml_enable_tags_s, const std::string& hrefxml_disable_tags_s)
224{
225 yarp::os::Bottle hrefxml_enable_tags_b;
226 hrefxml_enable_tags_b.fromString(hrefxml_enable_tags_s);
227 yarp::os::Bottle hrefxml_disable_tags_b;
228 hrefxml_disable_tags_b.fromString(hrefxml_disable_tags_s);
229 //yDebug() << "included enable tag size:" << b_included_enable_options.size() << " contents:" << b_included_enable_options.toString();
230 //yDebug() << "included disable tag size:" << b_included_disable_options.size() << " contents:" << b_included_disable_options.toString();
231
232 //if no `enabled_by` attribute are found in the xi::include line, then the include is enabled by default.
233 bool enabled = true;
234 size_t hrefxml_enable_tags_b_size = hrefxml_enable_tags_b.size();
235 if (hrefxml_enable_tags_b_size != 0)
236 {
237 //.otherwise, if a `enabled_by` attribute is found, then the include line is not enabled by default and it
238 // is enabled only if yarprobotinterface has been executed with the specific option --enable_tags
239 enabled = false;
240 for (size_t i = 0; i < hrefxml_enable_tags_b_size; i++)
241 {
242 std::string s = hrefxml_enable_tags_b.get(i).asString();
243 m_enable_set_found_in_all_xml.insert(s);
244 if (m_enabled_options_from_command_line.find(s) != m_enabled_options_from_command_line.end() ||
245 m_enabled_options_from_command_line.find("enable_all") != m_enabled_options_from_command_line.end())
246 {
247 enabled = true;
248 }
249 }
250 }
251 // if a `disabled_by` attribute is found, then the include line (either enabled by default or by an `enable_by` tag ) can
252 // be disabled if yarprobotinterface has been executed with the specific option --disable_tags
253 size_t hrefxml_disable_tags_b_size = hrefxml_disable_tags_b.size();
254 for (size_t i = 0; i < hrefxml_disable_tags_b_size; i++)
255 {
256 std::string s = hrefxml_disable_tags_b.get(i).asString();
257 m_disable_set_found_in_all_xml.insert(s);
258 if (m_disabled_options_from_command_line.find(s) != m_disabled_options_from_command_line.end())
259 {
260 enabled = false;
261 }
262 }
263
264 return enabled;
265}
266
267bool yarp::robotinterface::impl::XMLReaderFileV3::Private::PerformInclusions(TiXmlNode* pParent, const std::string& parent_fileName, const std::string& current_path)
268{
269loop_start: //goto label
270 for (TiXmlElement* childElem = pParent->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
271#ifdef DEBUG_PARSER
272 std::string a;
273 if (childElem->FirstAttribute())
274 a = childElem->FirstAttribute()->Value();
275 yDebug() << "Parsing" << childElem->Value() << a;
276#endif
277 std::string elemString = childElem->ValueStr();
278 if (elemString == "file") {
279 yFatal() << "'file' attribute is forbidden in yarprobotinterface DTD format 3.0. Error found in " << parent_fileName;
280 return false;
281 }
282
283 if (elemString == "xi:include")
284 {
285 std::string href_filename;
286 if (childElem->QueryStringAttribute("href", &href_filename) == TIXML_SUCCESS)
287 {
288 std::string href_enable_tags, href_disable_tags;
289 childElem->QueryStringAttribute("enabled_by", &href_enable_tags);
290 childElem->QueryStringAttribute("disabled_by", &href_disable_tags);
291 if (CheckIfIncludeSectionIsEnabled(href_enable_tags, href_disable_tags))
292 {
293 std::string included_path = std::string(current_path).append("\\").append(href_filename.substr(0, href_filename.find_last_of("\\/")));
294 std::string included_filename = href_filename.substr(href_filename.find_last_of("\\/") + 1);
295 std::string full_path_file = std::string(included_path).append("\\").append(included_filename);
296 TiXmlDocument included_file;
297
298 std::replace(full_path_file.begin(), full_path_file.end(), '\\', '/');
299 if (included_file.LoadFile(full_path_file))
300 {
301 PerformInclusions(included_file.RootElement(), included_filename, included_path);
302 //included_file.RootElement()->SetAttribute("xml:base", href_filename); //not yet implemented
303 included_file.RootElement()->RemoveAttribute("xmlns:xi");
304 if (pParent->ReplaceChild(childElem, *included_file.FirstChildElement()))
305 {
306 //the replace operation invalidates the iterator, hence we need to restart the parsing of this level
307 goto loop_start;
308 }
309 else
310 {
311 //fatal error
312 yFatal() << "Failed to include: " << included_filename << " in: " << parent_fileName;
313 return false;
314 }
315 }
316 else
317 {
318 //fatal error
319 yError() << included_file.ErrorDesc() << " file" << full_path_file << "included by " << parent_fileName << "at line" << childElem->Row();
320 yFatal() << "In file:" << included_filename << " included by: " << parent_fileName << " at line: " << childElem->Row();
321 return false;
322 }
323 }
324 else
325 {
326 yDebug() << "Skipping include section `" << href_filename << "` because is not enabled";
327 if (pParent->RemoveChild(childElem))
328 {
329 //the remove operation invalidates the iterator, hence we need to restart the parsing of this level
330 goto loop_start;
331 }
332 }
333 }
334 else
335 {
336 //fatal error
337 yFatal() << "Syntax error in: " << parent_fileName << " while searching for href attribute";
338 return false;
339 }
340 }
341 PerformInclusions(childElem, parent_fileName, current_path);
342 }
343 return true;
344}
345
347{
349 result.parsingIsSuccessful = true;
350
351 if (robotElem->ValueStr() != "robot") {
352 SYNTAX_ERROR(robotElem->Row()) << "Root element should be \"robot\". Found" << robotElem->ValueStr();
354 }
355
356 if (robotElem->QueryStringAttribute("name", &result.robot.name()) != TIXML_SUCCESS) {
357 SYNTAX_ERROR(robotElem->Row()) << R"("robot" element should contain the "name" attribute)";
359 }
360
361#if TINYXML_UNSIGNED_INT_BUG
362 if (robotElem->QueryUnsignedAttribute("build", &result.robot.build()) != TIXML_SUCCESS) {
363 // No build attribute. Assuming build="0"
364 SYNTAX_WARNING(robotElem->Row()) << "\"robot\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
365 }
366#else
367 int tmp;
368 if (robotElem->QueryIntAttribute("build", &tmp) != TIXML_SUCCESS || tmp < 0) {
369 // No build attribute. Assuming build="0"
370 SYNTAX_WARNING(robotElem->Row()) << R"("robot" element should contain the "build" attribute [unsigned int]. Assuming 0)";
371 tmp = 0;
372 }
373 result.robot.build() = static_cast<unsigned>(tmp);
374#endif
375
376 // If portprefix is already present in config we use that one
377 if (!config.check("portprefix"))
378 {
379 if (robotElem->QueryStringAttribute("portprefix", &result.robot.portprefix()) != TIXML_SUCCESS) {
380 SYNTAX_WARNING(robotElem->Row()) << R"("robot" element should contain the "portprefix" attribute. Using "name" attribute)";
381 result.robot.portprefix() = result.robot.name();
382 }
383 config.put("portprefix",result.robot.portprefix());
384 } else {
385 result.robot.portprefix() = config.find("portprefix").asString();
386 }
387
388 // FIXME DTD >= 4 Make this the default behaviour
389 bool reverse = false;
390 if (robotElem->QueryBoolAttribute("reverse-shutdown-action-order", &reverse) == TIXML_WRONG_TYPE) {
391 SYNTAX_ERROR(robotElem->Row()) << R"(The "reverse-shutdown-action-order" attribute in the "robot" element should be a bool.)";
393 }
394 result.robot.setReverseShutdownActionOrder(reverse);
395
396 // yDebug() << "Found robot [" << robot.name() << "] build [" << robot.build() << "] portprefix [" << robot.portprefix() << "]";
397
398 for (TiXmlElement* childElem = robotElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
399 std::string elemString = childElem->ValueStr();
400 if (elemString == "device" || elemString == "devices") {
401 for (const auto& childDevice : readDevices(childElem, result)) {
402 result.robot.devices().push_back(childDevice);
403 }
404 } else {
405 for (const auto& childParam : readParams(childElem, result)) {
406 result.robot.params().push_back(childParam);
407 }
408 }
409 }
410
411 return result;
412}
413
414
417{
418 const std::string& valueStr = devicesElem->ValueStr();
419
420 if (valueStr == "device") {
421 // yDebug() << valueStr;
423 deviceList.push_back(readDeviceTag(devicesElem, result));
424 return deviceList;
425 }
426 if (valueStr == "devices") {
427 // "devices"
428 return readDevicesTag(devicesElem, result);
429 }
430
431 SYNTAX_ERROR(devicesElem->Row()) << R"(Expected "device" or "devices". Found)" << valueStr;
432 result.parsingIsSuccessful = false;
434}
435
438{
439 const std::string& valueStr = deviceElem->ValueStr();
440
441 if (valueStr != "device") {
442 SYNTAX_ERROR(deviceElem->Row()) << "Expected \"device\". Found" << valueStr;
443 result.parsingIsSuccessful = false;
445 }
446
448
449 if (deviceElem->QueryStringAttribute("name", &device.name()) != TIXML_SUCCESS) {
450 SYNTAX_ERROR(deviceElem->Row()) << R"("device" element should contain the "name" attribute)";
451 result.parsingIsSuccessful = false;
452 return device;
453 }
454
455 // yDebug() << "Found device [" << device.name() << "]";
456
457 if (deviceElem->QueryStringAttribute("type", &device.type()) != TIXML_SUCCESS) {
458 SYNTAX_ERROR(deviceElem->Row()) << R"("device" element should contain the "type" attribute)";
459 result.parsingIsSuccessful = false;
460 return device;
461 }
462
463 device.params().push_back(yarp::robotinterface::Param("robotName", result.robot.portprefix()));
464
465 for (TiXmlElement* childElem = deviceElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
466 if (childElem->ValueStr() == "action" || childElem->ValueStr() == "actions") {
467 for (const auto& childAction : readActions(childElem, result)) {
468 device.actions().push_back(childAction);
469 }
470 } else {
471 for (const auto& childParam : readParams(childElem, result)) {
472 device.params().push_back(childParam);
473 }
474 }
475 }
476
477 // yDebug() << device;
478 return device;
479}
480
483{
484 //const std::string &valueStr = devicesElem->ValueStr();
485
488
489 for (TiXmlElement* childElem = devicesElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
490 if (childElem->ValueStr() == "param" || childElem->ValueStr() == "group" || childElem->ValueStr() == "paramlist" || childElem->ValueStr() == "params") {
491 for (const auto& childParam : readParams(childElem, result)) {
492 params.push_back(childParam);
493 }
494 } else {
495 for (const auto& childDevice : readDevices(childElem, result)) {
496 devices.push_back(childDevice);
497 }
498 }
499 }
500
501
502 for (auto& device : devices) {
503 device.params().insert(device.params().begin(), params.begin(), params.end());
504 }
505
506 return devices;
507}
508
511{
512 const std::string& valueStr = paramsElem->ValueStr();
513
514 if (valueStr == "param") {
516 params.push_back(readParamTag(paramsElem, result));
517 return params;
518 }
519 if (valueStr == "group") {
521 params.push_back(readGroupTag(paramsElem, result));
522 return params;
523 }
524 if (valueStr == "paramlist") {
525 return readParamListTag(paramsElem, result);
526 }
527 if (valueStr == "params") {
528 return readParamsTag(paramsElem, result);
529 }
530
531 SYNTAX_ERROR(paramsElem->Row()) << R"(Expected "param", "group", "paramlist", or "params". Found)" << valueStr;
532 result.parsingIsSuccessful = false;
534}
535
536void yarp::robotinterface::impl::XMLReaderFileV3::Private::ReplaceAllStrings(std::string& str, const std::string& from, const std::string& to)
537{
538 if(from.empty())
539 return;
540 size_t start_pos = 0;
541 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
542 str.replace(start_pos, from.length(), to);
543 start_pos += to.length();
544 }
545}
546
547
550{
551 if (paramElem->ValueStr() != "param") {
552 SYNTAX_ERROR(paramElem->Row()) << "Expected \"param\". Found" << paramElem->ValueStr();
553 result.parsingIsSuccessful = false;
555 }
556
558
559 if (paramElem->QueryStringAttribute("name", &param.name()) != TIXML_SUCCESS) {
560 SYNTAX_ERROR(paramElem->Row()) << R"("param" element should contain the "name" attribute)";
561 result.parsingIsSuccessful = false;
563 }
564
565 // yDebug() << "Found param [" << param.name() << "]";
566
567 const char* valueText = paramElem->GetText();
568 if (!valueText) {
569 SYNTAX_ERROR(paramElem->Row()) << R"("param" element should have a value [ "name" = )" << param.name() << "]";
570 result.parsingIsSuccessful = false;
572 }
573
574 // First process extern-name
575 std::string extern_name;
576 if (paramElem->QueryStringAttribute("extern-name", &extern_name) == TIXML_SUCCESS && config.check(extern_name)) {
577 // FIXME Check DTD >= 3.1
578 if (config.find(extern_name).isList())
579 {
580 param.value() = "(" + config.find(extern_name).asList()->toString() + ")";
581 }
582 else
583 {
584 param.value() = config.find(extern_name).toString();
585 }
586 } else {
587 param.value() = valueText;
588 }
589
590 // After process ${portprefix}
591 std::string paramValueBefore = param.value();
592 std::string paramValueAfter = paramValueBefore;
593 std::string portprefix = config.find("portprefix").toString();
594 ReplaceAllStrings(paramValueAfter, "${portprefix}", portprefix);
595 param.value() = paramValueAfter;
596
597
598
599 // yDebug() << param;
600 return param;
601}
602
605{
606 if (groupElem->ValueStr() != "group") {
607 SYNTAX_ERROR(groupElem->Row()) << "Expected \"group\". Found" << groupElem->ValueStr();
608 result.parsingIsSuccessful = false;
610 }
611
612 yarp::robotinterface::Param group(true);
613
614 if (groupElem->QueryStringAttribute("name", &group.name()) != TIXML_SUCCESS) {
615 SYNTAX_ERROR(groupElem->Row()) << R"("group" element should contain the "name" attribute)";
616 result.parsingIsSuccessful = false;
618 }
619
620 // yDebug() << "Found group [" << group.name() << "]";
621
623 for (TiXmlElement* childElem = groupElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
624 for (const auto& childParam : readParams(childElem, result)) {
625 params.push_back(childParam);
626 }
627 }
628 if (params.empty()) {
629 SYNTAX_ERROR(groupElem->Row()) << "\"group\" cannot be empty";
630 result.parsingIsSuccessful = false;
632 }
633
634 std::string groupString;
635 for (auto& param : params) {
636 if (!groupString.empty()) {
637 groupString += " ";
638 }
639 groupString += "(" + param.name() + " " + param.value() + ")";
640 }
641
642 group.value() = groupString;
643
644 return group;
645}
646
649{
650 if (paramListElem->ValueStr() != "paramlist") {
651 SYNTAX_ERROR(paramListElem->Row()) << "Expected \"paramlist\". Found" << paramListElem->ValueStr();
652 result.parsingIsSuccessful = false;
654 }
655
658
659 if (paramListElem->QueryStringAttribute("name", &mainparam.name()) != TIXML_SUCCESS) {
660 SYNTAX_ERROR(paramListElem->Row()) << R"("paramlist" element should contain the "name" attribute)";
661 result.parsingIsSuccessful = false;
663 }
664
665 params.push_back(mainparam);
666
667 // yDebug() << "Found paramlist [" << params.at(0).name() << "]";
668
669 for (TiXmlElement* childElem = paramListElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
670 if (childElem->ValueStr() != "elem") {
671 SYNTAX_ERROR(childElem->Row()) << "Expected \"elem\". Found" << childElem->ValueStr();
672 result.parsingIsSuccessful = false;
674 }
675
677
678 if (childElem->QueryStringAttribute("name", &childParam.name()) != TIXML_SUCCESS) {
679 SYNTAX_ERROR(childElem->Row()) << R"("elem" element should contain the "name" attribute)";
680 result.parsingIsSuccessful = false;
682 }
683
684 const char* valueText = childElem->GetText();
685 if (!valueText) {
686 SYNTAX_ERROR(childElem->Row()) << R"("elem" element should have a value [ "name" = )" << childParam.name() << "]";
687 result.parsingIsSuccessful = false;
689 }
690 childParam.value() = valueText;
691
692 params.push_back(childParam);
693 }
694
695 if (params.empty()) {
696 SYNTAX_ERROR(paramListElem->Row()) << "\"paramlist\" cannot be empty";
697 result.parsingIsSuccessful = false;
699 }
700
701 // +1 skips the first element, that is the main param
702 for (auto it = params.begin() + 1; it != params.end(); ++it) {
703 yarp::robotinterface::Param& param = *it;
704 params.at(0).value() += (params.at(0).value().empty() ? "(" : " ") + param.name();
705 }
706 params.at(0).value() += ")";
707
708 // yDebug() << params;
709 return params;
710}
711
714{
715 //const std::string &valueStr = paramsElem->ValueStr();
716
718 for (TiXmlElement* childElem = paramsElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
719 for (const auto & childParam : readParams(childElem, result)) {
720 params.push_back(childParam);
721 }
722 }
723
724 return params;
725}
726
729{
730 const std::string& valueStr = actionsElem->ValueStr();
731
732 if (valueStr != "action" && valueStr != "actions") {
733 SYNTAX_ERROR(actionsElem->Row()) << R"(Expected "action" or "actions". Found)" << valueStr;
734 }
735
736 if (valueStr == "action") {
738 actionList.push_back(readActionTag(actionsElem, result));
739 return actionList;
740 }
741 // "actions"
742 return readActionsTag(actionsElem, result);
743}
744
747{
748 if (actionElem->ValueStr() != "action") {
749 SYNTAX_ERROR(actionElem->Row()) << "Expected \"action\". Found" << actionElem->ValueStr();
750 result.parsingIsSuccessful = false;
752 }
753
755
756 if (actionElem->QueryValueAttribute<yarp::robotinterface::ActionPhase>("phase", &action.phase()) != TIXML_SUCCESS || action.phase() == yarp::robotinterface::ActionPhaseUnknown) {
757 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "phase" attribute [startup|interrupt{1,2,3}|shutdown])";
758 result.parsingIsSuccessful = false;
760 }
761
762
763 if (actionElem->QueryValueAttribute<yarp::robotinterface::ActionType>("type", &action.type()) != TIXML_SUCCESS || action.type() == yarp::robotinterface::ActionTypeUnknown) {
764 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "type" attribute [configure|calibrate|attach|abort|detach|park|custom])";
765 result.parsingIsSuccessful = false;
767 }
768
769 // yDebug() << "Found action [ ]";
770
771#if TINYXML_UNSIGNED_INT_BUG
772 if (actionElem->QueryUnsignedAttribute("level", &action.level()) != TIXML_SUCCESS) {
773 SYNTAX_ERROR(actionElem->Row()) << "\"action\" element should contain the \"level\" attribute [unsigned int]";
774 }
775#else
776 int tmp;
777 if (actionElem->QueryIntAttribute("level", &tmp) != TIXML_SUCCESS || tmp < 0) {
778 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "level" attribute [unsigned int])";
779 result.parsingIsSuccessful = false;
781 }
782 action.level() = static_cast<unsigned>(tmp);
783#endif
784
785 for (TiXmlElement* childElem = actionElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
786 for (const auto& childParam : readParams(childElem, result)) {
787 action.params().push_back(childParam);
788 }
789 }
790
791 // yDebug() << action;
792 return action;
793}
794
797{
798 //const std::string &valueStr = actionsElem->ValueStr();
799
800 std::string robotName;
801 if (actionsElem->QueryStringAttribute("robot", &robotName) != TIXML_SUCCESS) {
802 SYNTAX_WARNING(actionsElem->Row()) << R"("actions" element should contain the "robot" attribute)";
803 }
804
805 if (robotName != result.robot.name()) {
806 SYNTAX_WARNING(actionsElem->Row()) << "Trying to import a file for the wrong robot. Found" << robotName << "instead of" << result.robot.name();
807 }
808
809 unsigned int build;
810#if TINYXML_UNSIGNED_INT_BUG
811 if (actionsElem->QueryUnsignedAttribute("build", &build()) != TIXML_SUCCESS) {
812 // No build attribute. Assuming build="0"
813 SYNTAX_WARNING(actionsElem->Row()) << "\"actions\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
814 }
815#else
816 int tmp;
817 if (actionsElem->QueryIntAttribute("build", &tmp) != TIXML_SUCCESS || tmp < 0) {
818 // No build attribute. Assuming build="0"
819 SYNTAX_WARNING(actionsElem->Row()) << R"("actions" element should contain the "build" attribute [unsigned int]. Assuming 0)";
820 tmp = 0;
821 }
822 build = static_cast<unsigned>(tmp);
823#endif
824
825 if (build != result.robot.build()) {
826 SYNTAX_WARNING(actionsElem->Row()) << "Import a file for a different robot build. Found" << build << "instead of" << result.robot.build();
827 }
828
830 for (TiXmlElement* childElem = actionsElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
831 for (const auto & childAction : readActions(childElem, result)) {
832 actions.push_back(childAction);
833 }
834 }
835
836 return actions;
837}
838
839
841 const yarp::os::Searchable& config,
842 bool verb)
843{
844 mPriv->config.fromString(config.toString());
845 mPriv->verbose_output = verb;
846 auto ret = mPriv->readRobotFromFile(filename);
847 mPriv->config.clear();
848 return ret;
849}
850
852 const yarp::os::Searchable& config,
853 bool verb)
854{
855 mPriv->config.fromString(config.toString());
856 mPriv->verbose_output = verb;
857 auto ret = mPriv->readRobotFromString(xmlString);
858 mPriv->config.clear();
859 return ret;
860}
861
862
867
bool ret
#define yInfo(...)
Definition Log.h:319
#define yError(...)
Definition Log.h:361
#define yDebug(...)
Definition Log.h:275
#define yFatal(...)
Definition Log.h:382
#define SYNTAX_ERROR(line)
#define SYNTAX_WARNING(line)
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void fromString(const std::string &text)
Initializes bottle from a string.
Definition Bottle.cpp:204
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:251
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition Bottle.cpp:211
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition Bottle.cpp:287
A class for storing options and configuration information.
Definition Property.h:33
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
void clear()
Remove all associations.
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Bottle * asList() const
Get list value.
Definition Value.cpp:240
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
unsigned int & level()
Definition Action.cpp:102
ActionPhase & phase()
Definition Action.cpp:92
std::string & name()
Definition Param.cpp:80
std::string & value()
Definition Param.cpp:85
std::string & portprefix()
Definition Robot.cpp:520
DeviceList & devices()
Definition Robot.cpp:562
void setReverseShutdownActionOrder(bool reverseShutdownActionOrder)
Definition Robot.cpp:552
std::string & name()
Definition Robot.cpp:510
unsigned int & build()
Definition Robot.cpp:515
Result of the parsing of yarp::robotinterface::XMLReader.
Definition XMLReader.h:26
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
Definition XMLReader.h:38
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
Definition XMLReader.h:43
static XMLReaderResult ParsingFailed()
Definition XMLReader.h:28
void ReplaceAllStrings(std::string &str, const std::string &from, const std::string &to)
yarp::robotinterface::Device readDeviceTag(TiXmlElement *deviceElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Param readParamTag(TiXmlElement *paramElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromString(const std::string &xmlString)
yarp::robotinterface::ActionList readActionsTag(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevices(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamListTag(TiXmlElement *paramListElem, yarp::robotinterface::XMLReaderResult &result)
bool PerformInclusions(TiXmlNode *pParent, const std::string &parent_fileName, const std::string &current_path)
yarp::robotinterface::XMLReaderResult readRobotTag(TiXmlElement *robotElem)
bool CheckIfIncludeSectionIsEnabled(const std::string &href_enable_tags, const std::string &href_disable_tags)
yarp::robotinterface::Param readGroupTag(TiXmlElement *groupElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParams(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesTag(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActions(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Action readActionTag(TiXmlElement *actionElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamsTag(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromFile(const std::string &fileName)
yarp::robotinterface::XMLReaderResult getRobotFromString(const std::string &xmlString, const yarp::os::Searchable &config, bool verbose=false) override
yarp::robotinterface::XMLReaderResult getRobotFromFile(const std::string &filename, const yarp::os::Searchable &config, bool verbose=false) override
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
std::string DocTypeToString(RobotInterfaceDTD::DocType doctype)
std::vector< robotinterface::Action > ActionList
Definition Types.h:31
std::vector< robotinterface::Param > ParamList
Definition Types.h:30
std::vector< robotinterface::Device > DeviceList
Definition Types.h:32