配置文件yaml学习笔记

http://nodeca.github.io/js-yaml/
参考博客

 - 语法
 - ----------------
 - 大小写敏感
 - 使用缩进表示层级关系
 - 缩进不能使用tab按键,只能用空格
 - #表示注释
 - 相同层级元素  左侧对齐
 - 
 - 数据结构
 - -----------------
 - 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
 - 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
 - 纯量(scalars):单个的、不可再分的值
%yaml 1.2
---
username : wjw   #如果字符串中间包括空格和特殊字符 ,需要放在引号之中 '  字符串  ' ,单引号和双引号都可以使用,但双引号不会对特殊字符转义
age : !!str 30 #   !!  两个感叹号表示强制类型转换
score : !!float 13.0
male : true
book : null #null可以用 ~ 表示
bir : 1998-11-11 11:11:11
num : 1.34e+2
interest : 
   - basketball
   - football
friends :
  - name : a
    age : 18
  - name : b
    age : 19
relation :
  father : m
  mother : w


commont :
 asdasdad
 asdasd
 asd
commont2: >  #多行字符串  使用 >  折叠换行
 qweqweqwe
 qweq
 qwe
commont3: |  #保留换行符
 qweqweqwe
 qweq
 qwe
 
 
 
father : &father_info #锚点&和别名*,可以用来引用
 name : w
 age: 30
monitor: 
  <<: *father_info  #表示合并到当前数据,*用来引用锚点
... #用三个点来表示文件结束

yaml的解析

Node 是yaml-cpp中的核心概念,是最重要的数据结构,它用于存储解析后的 yaml 信息。Node一共有以下几种type:

Null 空节点

Sequence 序列,类似于一个Vector,对应YAML格式中的数组

Map 类似标准库中的Map,对应YAML格式中的对象

Scalar 标量,对应YAML格式中的常量

生成Node的形式有很多种,LoadFile()是最常见的一种
Node LoadFile( const std::string& filename);

filename就是yaml文件的路径。
有了 Node 之后,所有的信息都可以检索到。比如 name.

cout<<"name: "<<config["name"].as<string>() << endl;

as() 表示将解析的内容转换成string类型。
也可以转换成其他类型,他是一个模板方法。


yaml文件的解析

比如有配置文件config.yaml

name: frank
sex: male
age: 18
 
skills: 
  c++: 1
  java: 1
  android: 1
  python: 1

解析代码yaml_test.cpp

#include <iostream>
#include "yaml-cpp/yaml.h"
#include <fstream>
 
using namespace std;
 
int main(int argc,char** argv)
{
    YAML::Node config;
    try{
         config = YAML::LoadFile("../config.yaml");
    }catch(YAML::BadFile &e){
        std::cout<<"read error!"<<std::endl;
        return -1;
    }
    
    cout << "Node type " << config.Type() << endl;
    cout << "skills type " << config["skills"].Type() << endl;
 
    //可以用string类型作为下表,读取参数
    string age = "age";
    cout << "age when string is label:" << config[age].as<int>() << endl;
 
    cout << "name:" << config["name"].as<string>() << endl;
    cout << "sex:" << config["sex"].as<string>() << endl;
    cout << "age:" << config["age"].as<int>() << endl;
 
    //读取不存在的node值,报YAML::TypedBadConversion异常
    try{
        string label = config["label"].as<string>();
    }catch(YAML::TypedBadConversion<string> &e){
        std::cout<<"label node is NULL"<<std::endl;
    }//TypedBadConversion是模板类,读取什么类型的参数就传入什么类型
 
 
    cout << "skills c++:" << config["skills"]["c++"].as<int>() << endl;
    cout << "skills java:" << config["skills"]["java"].as<int>() << endl;
    cout << "skills android:" << config["skills"]["android"].as<int>() << endl;
    cout << "skills python:" << config["skills"]["python"].as<int>() << endl;
 
    for(YAML::const_iterator it= config["skills"].begin(); it != config["skills"].end();++it)
    {
        cout << it->first.as<string>() << ":" << it->second.as<int>() << endl;
    }
 
    YAML::Node test1 = YAML::Load("[1,2,3,4]");
    cout << " Type: " << test1.Type() << endl;
 
    YAML::Node test2 = YAML::Load("1");
    cout << " Type: " << test2.Type() << endl;
 
    YAML::Node test3 = YAML::Load("{'id':1,'degree':'senior'}");
    cout << " Type: " << test3.Type() << endl;
 
    ofstream fout("./testconfig.yaml"); //保存config为yaml文件
 
    config["score"] = 99;//添加新元素
 
    fout << config;
 
    fout.close();
 
 
    return 0;
}

Node的增删改查
#include <fstream>
#include <yaml-cpp/yaml.h>
#include <iostream>
#include <assert.h>
 
int main()
{
    YAML::Node node;  
    assert(node.IsNull());  //初始化的节点是Null类型
    node["key"] = "value";  //当你给它赋值键值对,它转变为Map类型
    //node.force_insert("key", "value");//这个操作和上面等价,但是它不会检查是否存在"key"键,不推荐使用
    if(node["mascot"])
        std::cout << node["mascot"].as<std::string>() << "\n";//单纯的查询操作不会增加一个key,当然上面的if不会执行
 
    node["number"] = 255;
    assert(node.IsMap());   //node是一个Map
    node["seq"].push_back("first element");
    node["seq"].push_back("second element");//node的seq下是Sequence类型,有两个参数
 
    YAML::Node node_2;  
    node_2.push_back("first item");//如果你不给node_2键值对,它是一个sequence类型
    node_2.push_back("second_item");
    node_2.push_back("third_item");
    std::vector<int> v = {1,3,5,7,9};//给node_2插入了一个Sequence
    node_2.push_back(v);
    assert(node_2.IsSequence());//当然,node_2仍然是一个Sequence
 
    assert(node_2[0].as<std::string>() == "first item");
    //对于Sequence类型,你可以使用它的下标来访问
    //注意这里as<T>是一个模板转换,node_2[0]的type是NodeType::Scalar
    auto it = node_2.begin();
    for(; it != node_2.end(); it++)
        std::cout << *(it) << std::endl;
    //当然,你也可以用迭代器来访问
    //他们的类型分别是NodeType::Scalar,NodeType::Scalar,NodeType::Scalar,NodeType::Sequence
    //取值时记得使用as进行模板转换
    node_2["key"] = "value";
    assert(node_2.IsMap());//一旦node_2接收到键值对,它转变为Map类型
    assert(node_2[0].as<std::string>() == "first item");//此时,Sequence时的下标变为它的key值
    node["node_2"] = node_2;//将node_2作为node的一个子项
    node["pointer_to_first_element"] = node["seq"][0];//你也可以给已有的node设置一个别名,类似于一个指针
    assert(node["pointer_to_first_element"].as<std::string>() == "first element");//你可以通过这个指针访问那个node
 
    node.remove(node["seq"][0]);//你可以通过指定一个node来删除它
    node.remove("pointer_to_first_element");//你也可以通过指定key来删除它
}

执行
std :: cout << node << endl;
结果如下:

key: value
number: 255
seq:
  - first element
  - second element
node_2:
  0: first item
  1: second_item
  2: third_item
  3:
    - 1
    - 3
    - 5
    - 7
    - 9
  key: value
yaml-cpp中的迭代

yaml-cpp 中也可以通过迭代的方式,访问 Node 中的内容。
比如,访问 skills 下面的各个元素。

for(YAML::const_iterator it= config["skills"].begin(); it != config["skills"].end();++it)
{
    cout << it->first.as<string>() << ":" << it->second.as<int>() << endl;
}

用 begin() 获取迭代器,用 end() 判断迭代器是否结束。

NodeType类型

yaml 支持 Scalar、List、Map 类型,yaml-cpp 通过 NodeType 定义了 Node 的可能类型。

namespace YAML {
struct NodeType {
  enum value { Undefined, Null, Scalar, Sequence, Map };
  //对应未定义、空、标量、序列、字典。
};
}
//判断NodeType
YAML::Node test1 = YAML::Load("[1,2,3,4]");
cout << " Type: " << test1.Type() << endl;
 
YAML::Node test2 = YAML::Load("1");
cout << " Type: " << test2.Type() << endl;
 
YAML::Node test3 = YAML::Load("{'id':1,'degree':'senior'}");
cout << " Type: " << test3.Type() << endl;

//结果显示:
 Type: 3
 Type: 2
 Type: 4
//分别对应 Sequence、Scalar、Map。
yaml文件的保存与读取

除了读取配置参数,还需要保存参数
Node可以使用文件流的方式进行读写,保存一个node可以用下面的方法:

std::ofstream fout("config.yaml");
...//设置配置文件node数据
fout << node <<std::endl;
fout.close();

上面打印到cout的内容会被输出到config.yaml文件。
读取一个node:

std::ifstream file("config.yaml");
YAML::Node node = YAML::Load(file);//读取来自test.yaml的node文件
std::cout << node <<std::endl;
//或者
YAML::Node node_2 = YAML::LoadFile("config.yaml");//也可以这样读取文件
std::cout << node_2["node_2"] <<std::endl;//可以直接用下标访问
for(auto it = node_2.begin(); it != node_2.end(); it++)
    std::cout << it->first << it->second << std::endl;//也可以用迭代器访问
在ROS中使用yaml

在ROS中使用,需要对CMakeLists.txt修改,增加yaml-cpp库,且使用一个roslib的package,设置yaml文件的路径。

link_libraries(yaml-cpp)
find_package(catkin REQUIRED COMPONENTS
  roslib
)

源文件中添加头文件#include <ros/package.h>

#include <ros/package.h>
......
std::string dir_package, dir_package_file;
dir_package = ros::package::getPath("xxx");
dir_package_file = dir_package + "/config/test.yaml";
loadYamlFile(dir_package_file);  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Loafer_W

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值