27#define SYNTAX_ERROR(line) yFatal() << "Syntax error while loading" << curr_filename << "at line" << line << "."
28#define SYNTAX_WARNING(line) yWarning() << "Invalid syntax while loading" << curr_filename << "at line" << line << "."
33#define TINYXML_UNSIGNED_INT_BUG 0
91 std::replace(filename.begin(), filename.end(),
'/',
'\\');
94 curr_filename = fileName;
96 path = filename.substr(0, filename.rfind(
"\\"));
98 path = filename.substr(0, filename.rfind(
'/'));
101 yDebug() <<
"Reading file" << filename.c_str();
102 auto* doc =
new TiXmlDocument(filename.c_str());
103 if (!doc->LoadFile()) {
108 if (!doc->RootElement()) {
114 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
115 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
116 if (dtd.parse(childNode->ToUnknown(), curr_filename)) {
123 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
133 if (dtd.majorVersion != 1 || dtd.minorVersion != 0) {
134 SYNTAX_WARNING(doc->Row()) <<
"Only yarprobotinterface DTD version 1.0 is supported";
148 curr_filename =
" XML runtime string ";
149 auto* doc =
new TiXmlDocument();
150 if (!doc->Parse(xmlString.c_str())) {
155 if (!doc->RootElement()) {
172 if (robotElem->ValueStr() !=
"robot") {
173 SYNTAX_ERROR(robotElem->Row()) <<
"Root element should be \"robot\". Found" << robotElem->ValueStr();
177 if (robotElem->QueryStringAttribute(
"name", &result.
robot.
name()) != TIXML_SUCCESS) {
178 SYNTAX_ERROR(robotElem->Row()) << R
"("robot" element should contain the "name" attribute)";
182#if TINYXML_UNSIGNED_INT_BUG
183 if (robotElem->QueryUnsignedAttribute(
"build", &robot.build()) != TIXML_SUCCESS) {
185 SYNTAX_WARNING(robotElem->Row()) <<
"\"robot\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
189 if (robotElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
191 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "build" attribute [unsigned int]. Assuming 0)";
194 result.robot.build() = static_cast<unsigned>(tmp);
197 if (robotElem->QueryStringAttribute(
"portprefix", &result.
robot.
portprefix()) != TIXML_SUCCESS) {
198 SYNTAX_WARNING(robotElem->Row()) << R
"("robot" element should contain the "portprefix" attribute. Using "name" attribute)";
204 for (TiXmlElement* childElem = robotElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
205 if (childElem->ValueStr() ==
"device" || childElem->ValueStr() ==
"devices") {
206 for (
const auto& childDevice : readDevices(childElem, result)) {
210 for (
const auto& childParam : readParams(childElem, result)) {
223 const std::string& valueStr = devicesElem->ValueStr();
225 if (valueStr ==
"device") {
228 deviceList.push_back(readDeviceTag(devicesElem, result));
232 if (valueStr ==
"devices") {
234 return readDevicesTag(devicesElem, result);
237 SYNTAX_ERROR(devicesElem->Row()) << R
"(Expected "device" or "devices". Found)" << valueStr;
245 const std::string& valueStr = deviceElem->ValueStr();
247 if (valueStr !=
"device") {
248 SYNTAX_ERROR(deviceElem->Row()) <<
"Expected \"device\". Found" << valueStr;
254 if (deviceElem->QueryStringAttribute(
"name", &device.
name()) != TIXML_SUCCESS) {
255 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "name" attribute)";
261 if (deviceElem->QueryStringAttribute(
"type", &device.
type()) != TIXML_SUCCESS) {
262 SYNTAX_ERROR(deviceElem->Row()) << R
"("device" element should contain the "type" attribute)";
268 for (TiXmlElement* childElem = deviceElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
269 if (childElem->ValueStr() ==
"action" || childElem->ValueStr() ==
"actions") {
270 for (
const auto& childAction : readActions(childElem, result)) {
271 device.
actions().push_back(childAction);
274 for (
const auto& childParam : readParams(childElem, result)) {
275 device.
params().push_back(childParam);
287 std::string filename;
288 if (devicesElem->QueryStringAttribute(
"file", &filename) == TIXML_SUCCESS) {
291 std::replace(filename.begin(), filename.end(),
'/',
'\\');
292 filename = path +
"\\" + filename;
294 filename = path +
"/" + filename;
296 return readDevicesFile(filename, result);
300 for (TiXmlElement* childElem = devicesElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
301 for (
const auto& childDevice : readDevices(childElem, result)) {
302 devices.push_back(childDevice);
312 std::string old_filename = curr_filename;
313 curr_filename = fileName;
315 yDebug() <<
"Reading file" << fileName.c_str();
316 auto* doc =
new TiXmlDocument(fileName.c_str());
317 if (!doc->LoadFile()) {
321 if (!doc->RootElement()) {
327 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
328 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
329 if (devicesFileDTD.
parse(childNode->ToUnknown(), curr_filename)) {
335 if (!devicesFileDTD.
valid()) {
336 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
347 SYNTAX_ERROR(doc->Row()) <<
"Trying to import a file with a different yarprobotinterface DTD version";
353 curr_filename = old_filename;
361 const std::string& valueStr = paramsElem->ValueStr();
363 if (valueStr ==
"param") {
365 params.push_back(readParamTag(paramsElem, result));
368 if (valueStr ==
"group") {
370 params.push_back(readGroupTag(paramsElem, result));
373 if (valueStr ==
"paramlist") {
374 return readParamListTag(paramsElem, result);
376 if (valueStr ==
"subdevice") {
377 return readSubDeviceTag(paramsElem, result);
379 if (valueStr ==
"params") {
380 return readParamsTag(paramsElem, result);
382 SYNTAX_ERROR(paramsElem->Row()) << R
"(Expected "param", "group", "paramlist", "subdevice", or "params". Found)" << valueStr;
390 if (paramElem->ValueStr() !=
"param") {
391 SYNTAX_ERROR(paramElem->Row()) <<
"Expected \"param\". Found" << paramElem->ValueStr();
397 if (paramElem->QueryStringAttribute(
"name", ¶m.
name()) != TIXML_SUCCESS) {
398 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should contain the "name" attribute)";
404 const char* valueText = paramElem->GetText();
406 SYNTAX_ERROR(paramElem->Row()) << R
"("param" element should have a value [ "name" = )" << param.name() << "]";
408 param.
value() = valueText;
418 if (groupElem->ValueStr() !=
"group") {
419 SYNTAX_ERROR(groupElem->Row()) <<
"Expected \"group\". Found" << groupElem->ValueStr();
425 if (groupElem->QueryStringAttribute(
"name", &group.
name()) != TIXML_SUCCESS) {
426 SYNTAX_ERROR(groupElem->Row()) << R
"("group" element should contain the "name" attribute)";
433 for (TiXmlElement* childElem = groupElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
434 for (
const auto& childParam : readParams(childElem, result)) {
435 params.push_back(childParam);
438 if (params.empty()) {
439 SYNTAX_ERROR(groupElem->Row()) <<
"\"group\" cannot be empty";
442 std::string groupString;
443 for (
auto& param : params) {
444 if (!groupString.empty()) {
447 groupString +=
"(" + param.name() +
" " + param.value() +
")";
450 group.
value() = groupString;
458 if (paramListElem->ValueStr() !=
"paramlist") {
459 SYNTAX_ERROR(paramListElem->Row()) <<
"Expected \"paramlist\". Found" << paramListElem->ValueStr();
466 if (paramListElem->QueryStringAttribute(
"name", &mainparam.
name()) != TIXML_SUCCESS) {
467 SYNTAX_ERROR(paramListElem->Row()) << R
"("paramlist" element should contain the "name" attribute)";
471 params.push_back(mainparam);
475 for (TiXmlElement* childElem = paramListElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
476 if (childElem->ValueStr() !=
"elem") {
477 SYNTAX_ERROR(childElem->Row()) <<
"Expected \"elem\". Found" << childElem->ValueStr();
482 if (childElem->QueryStringAttribute(
"name", &childParam.
name()) != TIXML_SUCCESS) {
483 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should contain the "name" attribute)";
487 const char* valueText = childElem->GetText();
489 SYNTAX_ERROR(childElem->Row()) << R
"("elem" element should have a value [ "name" = )" << childParam.name() << "]";
492 childParam.
value() = valueText;
495 params.push_back(childParam);
498 if (params.empty()) {
499 SYNTAX_ERROR(paramListElem->Row()) <<
"\"paramlist\" cannot be empty";
504 for (
auto it = params.begin() + 1; it != params.end(); ++it) {
506 params.at(0).
value() += (params.at(0).value().empty() ?
"(" :
" ") + param.
name();
508 params.at(0).value() +=
")";
517 if (subDeviceElem->ValueStr() !=
"subdevice") {
518 SYNTAX_ERROR(subDeviceElem->Row()) <<
"Expected \"subdevice\". Found" << subDeviceElem->ValueStr();
528 subDeviceParam.
name() =
"subdevice";
534 if (subDeviceElem->QueryStringAttribute(
"type", &subDeviceParam.
value()) != TIXML_SUCCESS) {
535 SYNTAX_ERROR(subDeviceElem->Row()) << R
"("subdevice" element should contain the "type" attribute)";
539 params.push_back(subDeviceParam);
543 for (TiXmlElement* childElem = subDeviceElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
544 for (
const auto& childParam : readParams(childElem, result)) {
558 std::string filename;
559 if (paramsElem->QueryStringAttribute(
"file", &filename) == TIXML_SUCCESS) {
562 std::replace(filename.begin(), filename.end(),
'/',
'\\');
563 filename = path +
"\\" + filename;
565 filename = path +
"/" + filename;
567 return readParamsFile(filename, result);
601 for (TiXmlElement* childElem = paramsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
602 for (
const auto & childParam : readParams(childElem, result)) {
603 params.push_back(childParam);
613 std::string old_filename = curr_filename;
614 curr_filename = fileName;
616 yDebug() <<
"Reading file" << fileName.c_str();
617 auto* doc =
new TiXmlDocument(fileName.c_str());
618 if (!doc->LoadFile()) {
624 if (!doc->RootElement()) {
632 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
633 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
634 if (paramsFileDTD.
parse(childNode->ToUnknown(), curr_filename)) {
640 if (!paramsFileDTD.
valid()) {
641 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
652 SYNTAX_ERROR(doc->Row()) <<
"Trying to import a file with a different yarprobotinterface DTD version";
658 curr_filename = old_filename;
665 const std::string& valueStr = actionsElem->ValueStr();
667 if (valueStr !=
"action" && valueStr !=
"actions") {
668 SYNTAX_ERROR(actionsElem->Row()) << R
"(Expected "action" or "actions". Found)" << valueStr;
671 if (valueStr ==
"action") {
673 actionList.push_back(readActionTag(actionsElem, result));
677 return readActionsTag(actionsElem, result);
683 if (actionElem->ValueStr() !=
"action") {
684 SYNTAX_ERROR(actionElem->Row()) <<
"Expected \"action\". Found" << actionElem->ValueStr();
690 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "phase" attribute [startup|interrupt{1,2,3}|shutdown])";
695 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "type" attribute [configure|calibrate|attach|abort|detach|park|custom])";
700#if TINYXML_UNSIGNED_INT_BUG
701 if (actionElem->QueryUnsignedAttribute(
"level", &action.
level()) != TIXML_SUCCESS) {
702 SYNTAX_ERROR(actionElem->Row()) <<
"\"action\" element should contain the \"level\" attribute [unsigned int]";
706 if (actionElem->QueryIntAttribute(
"level", &tmp) != TIXML_SUCCESS || tmp < 0) {
707 SYNTAX_ERROR(actionElem->Row()) << R
"("action" element should contain the "level" attribute [unsigned int])";
709 action.level() = static_cast<unsigned>(tmp);
712 for (TiXmlElement* childElem = actionElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
713 for (
const auto& childParam : readParams(childElem, result)) {
714 action.
params().push_back(childParam);
727 std::string filename;
728 if (actionsElem->QueryStringAttribute(
"file", &filename) == TIXML_SUCCESS) {
731 std::replace(filename.begin(), filename.end(),
'/',
'\\');
732 filename = path +
"\\" + filename;
734 filename = path +
"/" + filename;
736 return readActionsFile(filename, result);
739 std::string robotName;
740 if (actionsElem->QueryStringAttribute(
"robot", &robotName) != TIXML_SUCCESS) {
741 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "robot" attribute)";
745 SYNTAX_WARNING(actionsElem->Row()) <<
"Trying to import a file for the wrong robot. Found" << robotName <<
"instead of" << result.
robot.
name();
749#if TINYXML_UNSIGNED_INT_BUG
750 if (actionsElem->QueryUnsignedAttribute(
"build", &build()) != TIXML_SUCCESS) {
752 SYNTAX_WARNING(actionsElem->Row()) <<
"\"actions\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
756 if (actionsElem->QueryIntAttribute(
"build", &tmp) != TIXML_SUCCESS || tmp < 0) {
758 SYNTAX_WARNING(actionsElem->Row()) << R
"("actions" element should contain the "build" attribute [unsigned int]. Assuming 0)";
761 build = static_cast<unsigned>(tmp);
765 SYNTAX_WARNING(actionsElem->Row()) <<
"Import a file for a different robot build. Found" << build <<
"instead of" << result.
robot.
build();
769 for (TiXmlElement* childElem = actionsElem->FirstChildElement(); childElem !=
nullptr; childElem = childElem->NextSiblingElement()) {
770 for (
const auto& childAction : readActions(childElem, result)) {
771 actions.push_back(childAction);
781 std::string old_filename = curr_filename;
782 curr_filename = fileName;
784 yDebug() <<
"Reading file" << fileName.c_str();
785 auto* doc =
new TiXmlDocument(fileName.c_str());
786 if (!doc->LoadFile()) {
790 if (!doc->RootElement()) {
796 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
797 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
798 if (actionsFileDTD.
parse(childNode->ToUnknown(), curr_filename)) {
804 if (!actionsFileDTD.
valid()) {
805 SYNTAX_WARNING(doc->Row()) <<
"No DTD found. Assuming version yarprobotinterfaceV1.0";
816 SYNTAX_ERROR(doc->Row()) <<
"Trying to import a file with a different yarprobotinterface DTD version";
822 curr_filename = old_filename;
#define SYNTAX_ERROR(line)
#define SYNTAX_WARNING(line)
A base class for nested structures that can be searched.
unsigned int majorVersion
bool parse(TiXmlUnknown *unknownNode, const std::string &curr_filename)
std::string & portprefix()
Result of the parsing of yarp::robotinterface::XMLReader.
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
static XMLReaderResult ParsingFailed()
yarp::robotinterface::Param readParamTag(TiXmlElement *paramElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Action readActionTag(TiXmlElement *actionElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromString(const std::string &xmlString)
yarp::robotinterface::DeviceList readDevices(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamListTag(TiXmlElement *paramListElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActionsTag(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActions(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParams(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Device readDeviceTag(TiXmlElement *deviceElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesTag(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamsFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
std::string curr_filename
yarp::robotinterface::Param readGroupTag(TiXmlElement *groupElem, yarp::robotinterface::XMLReaderResult &result)
XMLReaderFileV1 *const parent
yarp::robotinterface::XMLReaderResult readRobotFromFile(const std::string &fileName)
yarp::robotinterface::ParamList readParamsTag(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
unsigned int majorVersion
Private(XMLReaderFileV1 *parent)
yarp::robotinterface::XMLReaderResult readRobotTag(TiXmlElement *robotElem)
unsigned int minorVersion
yarp::robotinterface::ParamList readSubDeviceTag(TiXmlElement *subDeviceElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActionsFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult getRobotFromString(const std::string &xmlString, const yarp::os::Searchable &config, bool verbose=false) override
~XMLReaderFileV1() override
yarp::robotinterface::XMLReaderResult getRobotFromFile(const std::string &filename, const yarp::os::Searchable &config, bool verbose=false) override
std::string DocTypeToString(RobotInterfaceDTD::DocType doctype)
std::vector< robotinterface::Action > ActionList
std::vector< robotinterface::Param > ParamList
std::vector< robotinterface::Device > DeviceList