29 #define SYNTAX_ERROR(line) yError() << "Syntax error while loading" << curr_filename << "at line" << line << "."
30 #define SYNTAX_WARNING(line) yWarning() << "Invalid syntax while loading" << curr_filename << "at line" << line << "."
35 #define TINYXML_UNSIGNED_INT_BUG 0
62 bool PerformInclusions(TiXmlNode* pParent,
const std::string& parent_fileName,
const std::string& current_path);
89 yDebug() <<
"Reading file" << fileName.c_str();
90 auto* doc =
new TiXmlDocument(fileName.c_str());
91 if (!doc->LoadFile()) {
96 if (!doc->RootElement()) {
102 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
103 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
104 if (dtd.parse(childNode->ToUnknown(), curr_filename)) {
111 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
121 if (dtd.majorVersion != 1 || dtd.minorVersion != 0) {
122 SYNTAX_WARNING(doc->Row()) <<
"Only yarprobotinterface DTD version 1.0 is supported";
126 std::string current_path;
127 current_path = fileName.substr(0, fileName.find_last_of(
"\\/"));
128 std::string current_filename;
129 std::string log_filename;
130 current_filename = fileName.substr(fileName.find_last_of(
"\\/") + 1);
131 log_filename = current_filename.substr(0, current_filename.find(
".xml"));
132 log_filename +=
"_preprocessor_log.xml";
134 PerformInclusions(doc->RootElement(), current_filename, current_path);
136 std::string full_log_withpath = current_path + std::string(
"\\") + log_filename;
137 std::replace(full_log_withpath.begin(), full_log_withpath.end(),
'\\',
'/');
138 yDebug() <<
"Preprocessor complete in: " << end_time - start_time <<
"s";
139 if (verbose_output) {
140 yDebug() <<
"Preprocessor output stored in: " << full_log_withpath;
141 doc->SaveFile(full_log_withpath);
153 curr_filename =
" XML runtime string ";
154 auto* doc =
new TiXmlDocument();
155 if (!doc->Parse(xmlString.c_str())) {
160 if (!doc->RootElement()) {
174 for (TiXmlElement* childElem = pParent->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
177 if (childElem->FirstAttribute())
178 a = childElem->FirstAttribute()->Value();
179 yDebug() <<
"Parsing" << childElem->Value() << a;
181 std::string elemString = childElem->ValueStr();
182 if (elemString ==
"file") {
183 yFatal() <<
"'file' attribute is forbidden in yarprobotinterface DTD format 3.0. Error found in " << parent_fileName;
185 }
else if (elemString ==
"xi:include") {
186 std::string href_filename;
187 std::string included_filename;
188 std::string included_path;
189 if (childElem->QueryStringAttribute(
"href", &href_filename) == TIXML_SUCCESS) {
190 included_path = std::string(current_path).append(
"\\").append(href_filename.substr(0, href_filename.find_last_of(
"\\/")));
191 included_filename = href_filename.substr(href_filename.find_last_of(
"\\/") + 1);
192 std::string full_path_file = std::string(included_path).append(
"\\").append(included_filename);
193 TiXmlDocument included_file;
195 std::replace(full_path_file.begin(), full_path_file.end(),
'\\',
'/');
196 if (included_file.LoadFile(full_path_file)) {
197 PerformInclusions(included_file.RootElement(), included_filename, included_path);
199 included_file.RootElement()->RemoveAttribute(
"xmlns:xi");
200 if (pParent->ReplaceChild(childElem, *included_file.FirstChildElement())) {
205 yFatal() <<
"Failed to include: " << included_filename <<
" in: " << parent_fileName;
210 yError() << included_file.ErrorDesc() <<
" file" << full_path_file <<
"included by " << parent_fileName <<
"at line" << childElem->Row();
211 yFatal() <<
"In file:" << included_filename <<
" included by: " << parent_fileName <<
" at line: " << childElem->Row();
216 yFatal() <<
"Syntax error in: " << parent_fileName <<
" while searching for href attribute";
220 PerformInclusions(childElem, parent_fileName, current_path);
230 if (robotElem->ValueStr() !=
"robot") {
231 SYNTAX_ERROR(robotElem->Row()) <<
"Root element should be \"robot\". Found" << robotElem->ValueStr();
235 if (robotElem->QueryStringAttribute(
"name", &result.
robot.
name()) != TIXML_SUCCESS) {
236 SYNTAX_ERROR(robotElem->Row()) << R
"("robot" element should contain the "name" attribute)";
240 #if TINYXML_UNSIGNED_INT_BUG
241 if (robotElem->QueryUnsignedAttribute(
"build", &result.
robot.
build()) != TIXML_SUCCESS) {
243 SYNTAX_WARNING(robotElem->Row()) <<
"\"robot\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
247 if (robotElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
249 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "build" attribute [unsigned int]. Assuming 0)";
255 if (robotElem->QueryStringAttribute(
"portprefix", &result.
robot.
portprefix()) != TIXML_SUCCESS) {
256 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "portprefix" attribute. Using "name" attribute)";
262 for (TiXmlElement* childElem = robotElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
263 std::string elemString = childElem->ValueStr();
264 if (elemString ==
"device" || elemString ==
"devices") {
266 for (yarp::robotinterface::experimental::DeviceList::const_iterator it = childDevices.begin(); it != childDevices.end(); ++it) {
271 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
284 const std::string& valueStr = devicesElem->ValueStr();
286 if (valueStr ==
"device") {
289 deviceList.push_back(readDeviceTag(devicesElem, result));
291 }
else if (valueStr ==
"devices") {
293 return readDevicesTag(devicesElem, result);
295 SYNTAX_ERROR(devicesElem->Row()) << R
"(Expected "device" or "devices". Found)" << valueStr;
304 const std::string& valueStr = deviceElem->ValueStr();
306 if (valueStr !=
"device") {
307 SYNTAX_ERROR(deviceElem->Row()) <<
"Expected \"device\". Found" << valueStr;
314 if (deviceElem->QueryStringAttribute(
"name", &device.
name()) != TIXML_SUCCESS) {
315 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "name" attribute)";
322 if (deviceElem->QueryStringAttribute(
"type", &device.
type()) != TIXML_SUCCESS) {
323 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "type" attribute)";
330 for (TiXmlElement* childElem = deviceElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
331 if (childElem->ValueStr() ==
"action" || childElem->ValueStr() ==
"actions") {
333 for (yarp::robotinterface::experimental::ActionList::const_iterator it = childActions.begin(); it != childActions.end(); ++it) {
334 device.
actions().push_back(*it);
338 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
339 device.
params().push_back(*it);
354 for (TiXmlElement* childElem = devicesElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
356 for (yarp::robotinterface::experimental::DeviceList::const_iterator it = childDevices.begin(); it != childDevices.end(); ++it) {
357 devices.push_back(*it);
367 const std::string& valueStr = paramsElem->ValueStr();
369 if (valueStr ==
"param") {
371 params.push_back(readParamTag(paramsElem, result));
373 }
else if (valueStr ==
"group") {
375 params.push_back(readGroupTag(paramsElem, result));
377 }
else if (valueStr ==
"paramlist") {
378 return readParamListTag(paramsElem, result);
379 }
else if (valueStr ==
"subdevice") {
380 return readSubDeviceTag(paramsElem, result);
381 }
else if (valueStr ==
"params") {
382 return readParamsTag(paramsElem, result);
384 SYNTAX_ERROR(paramsElem->Row()) << R
"(Expected "param", "group", "paramlist", "subdevice", or "params". Found)" << valueStr;
394 if (paramElem->ValueStr() !=
"param") {
395 SYNTAX_ERROR(paramElem->Row()) <<
"Expected \"param\". Found" << paramElem->ValueStr();
402 if (paramElem->QueryStringAttribute(
"name", ¶m.
name()) != TIXML_SUCCESS) {
403 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should contain the "name" attribute)";
410 const char* valueText = paramElem->GetText();
412 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should have a value [ "name" = )" << param.name() << "]";
416 param.
value() = valueText;
425 if (groupElem->ValueStr() !=
"group") {
426 SYNTAX_ERROR(groupElem->Row()) <<
"Expected \"group\". Found" << groupElem->ValueStr();
433 if (groupElem->QueryStringAttribute(
"name", &group.
name()) != TIXML_SUCCESS) {
434 SYNTAX_ERROR(groupElem->Row()) << R
"("group" element should contain the "name" attribute)";
442 for (TiXmlElement* childElem = groupElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
444 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
445 params.push_back(*it);
448 if (params.empty()) {
449 SYNTAX_ERROR(groupElem->Row()) <<
"\"group\" cannot be empty";
454 std::string groupString;
455 for (
auto& param : params) {
456 if (!groupString.empty()) {
459 groupString +=
"(" + param.name() +
" " + param.value() +
")";
462 group.
value() = groupString;
470 if (paramListElem->ValueStr() !=
"paramlist") {
471 SYNTAX_ERROR(paramListElem->Row()) <<
"Expected \"paramlist\". Found" << paramListElem->ValueStr();
479 if (paramListElem->QueryStringAttribute(
"name", &mainparam.
name()) != TIXML_SUCCESS) {
480 SYNTAX_ERROR(paramListElem->Row()) << R
"("paramlist" element should contain the "name" attribute)";
485 params.push_back(mainparam);
489 for (TiXmlElement* childElem = paramListElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
490 if (childElem->ValueStr() !=
"elem") {
491 SYNTAX_ERROR(childElem->Row()) <<
"Expected \"elem\". Found" << childElem->ValueStr();
498 if (childElem->QueryStringAttribute(
"name", &childParam.
name()) != TIXML_SUCCESS) {
499 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should contain the "name" attribute)";
504 const char* valueText = childElem->GetText();
506 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should have a value [ "name" = )" << childParam.name() << "]";
510 childParam.
value() = valueText;
512 params.push_back(childParam);
515 if (params.empty()) {
516 SYNTAX_ERROR(paramListElem->Row()) <<
"\"paramlist\" cannot be empty";
522 for (
auto it = params.begin() + 1; it != params.end(); ++it) {
524 params.at(0).
value() += (params.at(0).value().empty() ?
"(" :
" ") + param.
name();
526 params.at(0).value() +=
")";
535 if (subDeviceElem->ValueStr() !=
"subdevice") {
536 SYNTAX_ERROR(subDeviceElem->Row()) <<
"Expected \"subdevice\". Found" << subDeviceElem->ValueStr();
547 subDeviceParam.
name() =
"subdevice";
553 if (subDeviceElem->QueryStringAttribute(
"type", &subDeviceParam.
value()) != TIXML_SUCCESS) {
554 SYNTAX_ERROR(subDeviceElem->Row()) << R
"("subdevice" element should contain the "type" attribute)";
560 params.push_back(subDeviceParam);
564 for (TiXmlElement* childElem = subDeviceElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
566 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
581 for (TiXmlElement* childElem = paramsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
583 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
584 params.push_back(*it);
594 const std::string& valueStr = actionsElem->ValueStr();
596 if (valueStr !=
"action" && valueStr !=
"actions") {
597 SYNTAX_ERROR(actionsElem->Row()) << R
"(Expected "action" or "actions". Found)" << valueStr;
600 if (valueStr ==
"action") {
602 actionList.push_back(readActionTag(actionsElem, result));
606 return readActionsTag(actionsElem, result);
612 if (actionElem->ValueStr() !=
"action") {
613 SYNTAX_ERROR(actionElem->Row()) <<
"Expected \"action\". Found" << actionElem->ValueStr();
621 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "phase" attribute [startup|interrupt{1,2,3}|shutdown])";
628 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "type" attribute [configure|calibrate|attach|abort|detach|park|custom])";
635 #if TINYXML_UNSIGNED_INT_BUG
636 if (actionElem->QueryUnsignedAttribute(
"level", &action.
level()) != TIXML_SUCCESS) {
637 SYNTAX_ERROR(actionElem->Row()) <<
"\"action\" element should contain the \"level\" attribute [unsigned int]";
641 if (actionElem->QueryIntAttribute(
"level", &tmp) != TIXML_SUCCESS || tmp < 0) {
642 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "level" attribute [unsigned int])";
646 action.
level() = (unsigned)tmp;
649 for (TiXmlElement* childElem = actionElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
651 for (yarp::robotinterface::experimental::ParamList::const_iterator it = childParams.begin(); it != childParams.end(); ++it) {
652 action.
params().push_back(*it);
665 std::string robotName;
666 if (actionsElem->QueryStringAttribute(
"robot", &robotName) != TIXML_SUCCESS) {
667 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "robot" attribute)";
671 SYNTAX_WARNING(actionsElem->Row()) <<
"Trying to import a file for the wrong robot. Found" << robotName <<
"instead of" << result.
robot.
name();
675 #if TINYXML_UNSIGNED_INT_BUG
676 if (actionsElem->QueryUnsignedAttribute(
"build", &build()) != TIXML_SUCCESS) {
678 SYNTAX_WARNING(actionsElem->Row()) <<
"\"actions\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
682 if (actionsElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
684 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "build" attribute [unsigned int]. Assuming 0)";
687 build = (unsigned)tmp;
691 SYNTAX_WARNING(actionsElem->Row()) <<
"Import a file for a different robot build. Found" << build <<
"instead of" << result.
robot.
build();
695 for (TiXmlElement* childElem = actionsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
697 for (yarp::robotinterface::experimental::ActionList::const_iterator it = childActions.begin(); it != childActions.end(); ++it) {
698 actions.push_back(*it);
#define SYNTAX_ERROR(line)
#define SYNTAX_WARNING(line)
std::string & portprefix()
Result of the parsing of XMLReader.
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
static XMLReaderResult ParsingFailed()
yarp::robotinterface::experimental::XMLReaderResult readRobotFromFile(const std::string &fileName)
yarp::robotinterface::experimental::Param readGroupTag(TiXmlElement *groupElem, yarp::robotinterface::experimental::XMLReaderResult &result)
unsigned int majorVersion
unsigned int minorVersion
yarp::robotinterface::experimental::ParamList readParamListTag(TiXmlElement *paramListElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::ActionList readActions(TiXmlElement *actionsElem, yarp::robotinterface::experimental::XMLReaderResult &result)
Private(XMLReaderFileV3 *parent)
bool PerformInclusions(TiXmlNode *pParent, const std::string &parent_fileName, const std::string ¤t_path)
yarp::robotinterface::experimental::DeviceList readDevicesTag(TiXmlElement *devicesElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::ParamList readSubDeviceTag(TiXmlElement *subDeviceElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::ParamList readParamsTag(TiXmlElement *paramsElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::ParamList readParams(TiXmlElement *paramsElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::DeviceList readDevices(TiXmlElement *devicesElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::Param readParamTag(TiXmlElement *paramElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::Action readActionTag(TiXmlElement *actionElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::XMLReaderResult readRobotFromString(const std::string &xmlString)
XMLReaderFileV3 *const parent
std::string curr_filename
yarp::robotinterface::experimental::ActionList readActionsTag(TiXmlElement *actionsElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::Device readDeviceTag(TiXmlElement *deviceElem, yarp::robotinterface::experimental::XMLReaderResult &result)
yarp::robotinterface::experimental::XMLReaderResult readRobotTag(TiXmlElement *robotElem)
yarp::robotinterface::experimental::XMLReaderResult getRobotFromFile(const std::string &filename, bool verbose=false) override
yarp::robotinterface::experimental::XMLReaderResult getRobotFromString(const std::string &xmlString, bool verbose=false) override
~XMLReaderFileV3() override
double now()
Return the current time in seconds, relative to an arbitrary starting point.
std::vector< robotinterface::experimental::Action > ActionList
std::vector< robotinterface::experimental::Device > DeviceList
std::vector< robotinterface::experimental::Param > ParamList
std::string DocTypeToString(RobotInterfaceDTD::DocType doctype)