yaml 使用自定义类型读取和写回文件 .as<struce> 和emitter 以及随机出现解析失败警告

一.意义
 yaml对于内容有类型判断,也可以通过!!进行指定类型,所以这给读取自定义结构类型的yaml读取提供了可以,而不是在yaml 0.5以后的版本中还需要重载一大堆的>>符号

二.参考资料
yaml-cpp官网
https://github.com/jbeder/yaml-cpp/wiki/Tutorial

node.Type()
-Null
-Scalar
-Sequence
-map
-undefined

三.读取
重载yaml命名空间里面的decode函数

struct Vec3 { double x, y, z;};
namespace YAML {
template<>
struct convert<Vec3> {
  static bool decode(const Node& node, Vec3& rhs) {
    if(!node.IsSequence() || node.size() != 3) {
      return false;
    }
    rhs.x = node[0].as<double>();
    rhs.y = node[1].as<double>();
    rhs.z = node[2].as<double>();
    return true;
  }
};
}
YAML::Node node = YAML::Load("start: [1, 3, 0]");
Vec3 v = node["start"].as<Vec3>();
node["end"] = Vec3(2, -1, 0);


来一个复杂一点的
yaml数据为:

-name:marry
 id:10
 sex:female
 workday:[1,2,5,6]

-name:dave
 id:11
 sex:male
 workday:[2,3,4,5]

定义结构体为

struct employee
{
 string name;
 int id;
 string sex;
 struct workDay{double one,two,three,four};
}

这个时候重载decode函数为   
//decode

//其实decode函数就是告诉yaml怎么把yaml读取后的数组的内容和自定义数据类型进行复制
static bool decode(const Node& node, employee& subdata) {//一个"-"表示一个node

    subdata.name = node[0].as<string>();
    subdata.id = node[1].as<int>();     //这个时候类型只能是int 否则也会解析失败
    subdata.sex = node[2].as<double>(); //还可以在decode里面做内容的判断
    if(subdata.sex!="male"||subdata.sex!="female")
    return false;//函数最后return false会throw 一个exception 需要话在使用node.as<employee>的时候使用try catch去捕获异常
    subData.workDay.one=node[3][0].as<double>();
    subData.workDay.two=node[3][1].as<double>();
    subData.workDay.three=node[3][2].as<double>();
    subData.workDay.four=node[3][3].as<double>();
    return true;
}


//解析失败原因
1.访问了一个node数组为空的项
2.内容类型和指定as解析的不同,例如 id=ss这个时候就会报错了 as支持c++八大基本类型
3.和decode函数里面设定的条件不同 sex=man 这个时候也会throw一个exception
通过try catch 抓住yaml exception&e之后 可以通过e.what来显示集体是哪一行出了问题
//可以用node["name"]同样能够读取的到

四、写回


yaml-cpp 0.5之后就不在使用encode这个重载函数,而是使用了一个emiter对象,所以需要在使用写回yaml文件的类中声明emiter的<<为重载函数
一个emiter就相当是一个文件对象 同样的<<主要就是声明怎么把 自定义的类型数据和node建立一一对应的联系

struct employee
{
 string name;
 int id;
 string sex;
 struct workDay{double one,two,three,four};
}
YAML::Emitter& operator << (YAML::Emitter& out, const employee& v) {
    <out<YAML::BeginSeq;//声明一个文件开始 --- 关于---和...可以参考https://blog.csdn.net/qq_34249583/article/details/81166216

    out << YAML::BeginMap
    out << YAML::Key<<"name";//name代表的是yaml文件里面的key名字和employee的name没有直接关联
    out << YAML::Value<<v.name;
    
    out <<YAML::Key<<"id";
        out <<YAML::Value<<v.id;

        out <<YAML::Key<<"sex"
        out <<YAML::Value<<v.sex;

        out <<YAML::Key<<"workDay";
        vector<double> workday<<v.workDay.one<<v.workDay.two<<v.workDay.three<<v.workDay.four;
    out <<YAML::Value<<YAML::Flow<<workday;
    out <<YAML::EndMap;

    out << YAML::EndSeq;//声明一个文件结束 ...
        return out;
}

写完对应关系之后就是使用
YAML::Emitter emit;
emit<<employee;
file<<emit.c_str();

五、随机失败警告

      解析字符有时候能够解析成功,但是有时候又会随机报错,这种情况通常来说是因为重载decode函数的时候,并不是所有路径上都有返回值,导致函数return了一个随机值,这个函数一旦return false,yaml-cpp就会丢出一个异常。

猜你喜欢

转载自blog.csdn.net/qq_34249583/article/details/81171558