-
Joaquim Casals Buñuel authoredJoaquim Casals Buñuel authored
parser_yaml.hpp 9.52 KiB
#ifndef PARSER_YAML_HPP
#define PARSER_YAML_HPP
#include "yaml-cpp/yaml.h"
#include <vector>
#include <regex>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
namespace {
// std::string remove_ws( const std::string& str ){
// std::string str_no_ws ;
// for( char c : str ) if( !std::isspace(c) ) str_no_ws += c ;
// return str_no_ws ;
// }
string parseSequence(YAML::Node n){
assert(n.Type() != YAML::NodeType::Map && "Trying to parse as a Sequence a Map node");
if(n.Type() == YAML::NodeType::Scalar) return n.Scalar();
string aux = "[";
bool first = true;
for(auto it : n){
if(first) {
aux = aux + parseSequence(it);
first = false;
}else{
aux = aux + "," + parseSequence(it);
}
}
aux = aux + "]";
return aux;
}
std::string mapToString(std::map<std::string,std::string> _map){
std::string result = "";
auto v = std::vector<string>();
std::transform(_map.begin(), _map.end(), back_inserter(v), [](const std::pair<string,string> p){return "{" + p.first + ":" + p.second + "}";});
auto concat = [](string ac, string str)-> string {
return ac + str + ",";
};
string aux = "";
string accumulated = std::accumulate(v.begin(), v.end(), aux, concat);
if(accumulated.size() > 1) accumulated = accumulated.substr(0,accumulated.size() - 1);
else accumulated = "";
return "[" + accumulated + "]";
}
}
class parserYAML {
struct ParamsInitSensor{
string _type;
string _name;
YAML::Node n;
};
struct ParamsInitProcessor{
string _type;
string _name;
string _name_assoc_sensor;
YAML::Node n;
};
map<string, string> _params;
string _active_name;
vector<ParamsInitSensor> _paramsSens;
vector<ParamsInitProcessor> _paramsProc;
vector<string> _files;
string _file;
public:
parserYAML(){
_params = map<string, string>();
_active_name = "";
_paramsSens = vector<ParamsInitSensor>();
_paramsProc = vector<ParamsInitProcessor>();
_file = "";
_files = vector<string>();
}
parserYAML(string file){
_params = map<string, string>();
_active_name = "";
_paramsSens = vector<ParamsInitSensor>();
_paramsProc = vector<ParamsInitProcessor>();
_files = vector<string>();
_file = file;
}
~parserYAML(){
//
}
void walkTree(string file);
void walkTree(string file, vector<string>& tags);
void walkTree(string file, vector<string>& tags, string hdr);
void walkTreeR(YAML::Node n, vector<string>& tags, string hdr);
void updateActiveName(string tag);
void parseFirstLevel(string file);
string tagsToString(vector<string>& tags);
vector<array<string, 2>> sensorsSerialization();
vector<array<string, 3>> processorsSerialization();
vector<string> getFiles();
map<string,string> getParams();
void parse();
map<string, string> fetchAsMap(YAML::Node);
};
string parserYAML::tagsToString(vector<std::string> &tags){
string hdr = "";
for(auto it : tags){
hdr = hdr + "/" + it;
}
return hdr;
}
void parserYAML::walkTree(string file){
YAML::Node n = YAML::LoadFile(file);
vector<string> hdrs = vector<string>();
walkTreeR(n, hdrs, "");
}
void parserYAML::walkTree(string file, vector<string>& tags){
YAML::Node n = YAML::LoadFile(file);
walkTreeR(n, tags, "");
}
void parserYAML::walkTree(string file, vector<string>& tags, string hdr){
YAML::Node n = YAML::LoadFile(file);
walkTreeR(n, tags, hdr);
}
void parserYAML::walkTreeR(YAML::Node n, vector<string>& tags, string hdr){
switch (n.Type()) {
case YAML::NodeType::Scalar : {
regex r("^@.*");
if(regex_match(n.Scalar(), r)){
string str = n.Scalar();
// cout << "SUBSTR " << str.substr(1,str.size() - 1);
walkTree(str.substr(1,str.size() - 1), tags, hdr);
}else{
// std::copy(tags.begin(), tags.end(), std::ostream_iterator<string>(std::cout, "¬"));
// cout << "«»" << n.Scalar() << endl;
_params.insert(pair<string,string>(hdr, n.Scalar()));
}
break;
}
case YAML::NodeType::Sequence : {
// cout << tags[tags.size() - 1] << "«»" << kv << endl;
// std::vector<double> vi = n.as<std::vector<double>>();
string aux = parseSequence(n);
_params.insert(pair<string,string>(hdr, aux));
break;
}
case YAML::NodeType::Map : {
for(const auto& kv : n){
//If the key's value starts with a $ (i.e. $key) then its value is parsed as a literal map,
//otherwise the parser recursively parses the map
regex r("^\\$.*");
if(not regex_match(kv.first.as<string>(), r)){
regex rr("follow");
if(not regex_match(kv.first.as<string>(), rr)) {
tags.push_back(kv.first.as<string>());
if(tags.size() == 2) this->updateActiveName(kv.first.as<string>());
walkTreeR(kv.second, tags, hdr +"/"+ kv.first.as<string>());
tags.pop_back();
if(tags.size() == 1) this->updateActiveName("");
}else{
walkTree(kv.second.as<string>(), tags, hdr);
}
}else{
string key = kv.first.as<string>();
key = key.substr(1,key.size() - 1);
auto fm = fetchAsMap(kv.second);
_params.insert(pair<string,string>(hdr + "/" + key, mapToString(fm)));
}
}
break;
}
default:
assert(1 == 0 && "Unsupported node Type at walkTreeR");
break;
}
}
void parserYAML::updateActiveName(string tag){
this->_active_name = tag;
}
void parserYAML::parseFirstLevel(string file){
YAML::Node n = YAML::LoadFile(file);
YAML::Node n_config = n["config"];
assert(n_config.Type() == YAML::NodeType::Map && "trying to parse config node but found a non-Map node");
for(const auto& kv : n_config["sensors"]){
ParamsInitSensor pSensor = {kv["type"].Scalar(), kv["name"].Scalar(), kv};
_paramsSens.push_back(pSensor);
}
for(const auto& kv : n_config["processors"]){
ParamsInitProcessor pProc = {kv["type"].Scalar(), kv["name"].Scalar(), kv["sensorname"].Scalar(), kv};
_paramsProc.push_back(pProc);
}
YAML::Node n_files = n["files"];
assert(n_files.Type() == YAML::NodeType::Sequence && "trying to parse files node but found a non-Sequence node");
for(const auto& kv : n_files){
_files.push_back(kv.Scalar());
}
}
vector<array<string, 2>> parserYAML::sensorsSerialization(){
vector<array<string, 2>> aux = vector<array<string, 2>>();
for(auto it : this->_paramsSens)
aux.push_back({{it._type,it._name}});
return aux;
}
vector<array<string, 3>> parserYAML::processorsSerialization(){
vector<array<string, 3>> aux = vector<array<string, 3>>();
for(auto it : this->_paramsProc)
aux.push_back({{it._type,it._name,it._name_assoc_sensor}});
return aux;
}
vector<string> parserYAML::getFiles(){
return this->_files;
}
map<string,string> parserYAML::getParams(){
map<string,string> rtn = _params;
return rtn;
}
void parserYAML::parse(){
this->parseFirstLevel(this->_file);
for(auto it : _paramsSens){
vector<string> tags = vector<string>();
// this->walkTreeR(it.n , tags , it._type + "/" + it._name);
this->walkTreeR(it.n , tags , it._name);
}
for(auto it : _paramsProc){
vector<string> tags = vector<string>();
// this->walkTreeR(it.n , tags , it._type + "/" + it._name);
this->walkTreeR(it.n , tags , it._name);
}
}
map<string, string> parserYAML::fetchAsMap(YAML::Node n){
assert(n.Type() == YAML::NodeType::Map && "trying to fetch as Map a non-Map node");
auto m = map<string, string>();
for(const auto& kv : n){
string key = kv.first.as<string>();
switch (kv.second.Type()) {
case YAML::NodeType::Scalar : {
string value = kv.second.Scalar();
m.insert(pair<string,string>(key, value));
break;
}
case YAML::NodeType::Sequence : {
// cout << tags[tags.size() - 1] << "«»" << kv << endl;
// std::vector<double> vi = n.as<std::vector<double>>();
string aux = parseSequence(kv.second);
m.insert(pair<string,string>(key, aux));
break;
}
case YAML::NodeType::Map : {
m = fetchAsMap(kv.second);
auto rtn = vector<string>();
std::transform(m.begin(), m.end(), back_inserter(rtn), [](const std::pair<string,string> v){return "{" + v.first + ":" + v.second + "}";});
auto concat = [](string ac, string str)-> string {
return ac + str + ",";
};
string aux = "";
string accumulated = std::accumulate(rtn.begin(), rtn.end(), aux, concat);
if(accumulated.size() > 1) accumulated = accumulated.substr(0,accumulated.size() - 1);
else accumulated = "";
m.insert(pair<string,string>(key, "[" + accumulated + "]"));
break;
}
default:
assert(1 == 0 && "Unsupported node Type at fetchAsMap");
break;
}
}
return m;
}
#endif