最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

yaml

互联网 admin 3浏览 0评论

yaml

1. YAML简介

1.1. 定义规则

YAML是专门用来写配置文件的语言,非常简洁和强大,比 JSON和xml格式要方便很多。

YAML语言(发音 /ˈjæməl/ )的设计目标,就是方便人类读写。它实质上是一种通用的数据串行化格式。它的基本语法规则如下

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略。

YAML支持的数据结构有三种。

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

1.2. 语法

key: value;kv之间有空格 k: v
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
字符串默认不使用引号表示。如果字符串之中包含空格或特殊字符,需要放在引号之中。
单引号和双引号都可以使用,双引号不会对特殊字符转义。
单引号之中如果还有单引号,必须连续使用两个单引号转义。
字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。

 

1.3. 常用解析库

一般常用yaml-cpp和OpenCV进行解析

相比yaml-cpp,OpenCV的优点是可以在YAML文件中存储矩阵,读出来就是cv::Mat格式;缺点是OpenCV要求YAML文件有一个特殊的头,与标准的YAML文件并不兼容。或者也可以理解为OpenCV定义了一种新的YAML格式。

2. 安装yaml-cpp

git clone .git
cd yaml-cpp
mkdir build && cd build
cmake .. && make -j
sudo make install

3. CMakeLists配置

find_package(yaml-cpp REQUIRED)
include_directories(${YAML_CPP_INCLUDE_DIR})
target_link_libraries(node_name yaml-cpp)

4. yaml的解析

4.1. Node

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>()表示将解析的内容转换成 string 类型。
你也可以转换成其它类型。

它是一个模板方法。

4.2. yaml文件的解析

比如这样一个配置文件config.yaml

name: frank
sex: male
age: 18skills: c++: 1java: 1android: 1python: 1
#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;
}

4.3. 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是一个Mapnode["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插入了一个Sequencenode_2.push_back(v);assert(node_2.IsSequence());//当然,node_2仍然是一个Sequenceassert(node_2[0].as<std::string>() == "first item");//对于Sequence类型,你可以使用它的下标来访问//注意这里as<T>是一个模板转换,node_2[0]的type是NodeType::Scalarauto 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");//你可以通过这个指针访问那个nodenode.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 item1: second_item2: third_item3:- 1- 3- 5- 7- 9key: value

4.4. yamlcpp中的迭代

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() 判断迭代器是否结束。

4.5. NodeType类型

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

namespace YAML {struct NodeType {enum value { Undefined, Null, Scalar, Sequence, Map };};
}

对应未定义、空、标量、序列、字典。

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;

上面的代码是为了判断 NodeType。

结果如下:

 Type: 3Type: 2Type: 4

分别对应 Sequence、Scalar、Map。

4.6. yaml-cpp写配置文件(yaml文件的保存与读取)

日常开发中,经常用yaml文件来做配置文件,除了读取配置参数,我们经常需要保存参数,yaml-cpp 自然也提供了相应的功能。

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;//也可以用迭代器访问

参考文献

C++ 解析yaml文件的使用方法_sunlin972913894的博客-CSDN博客_c yaml

在cmakelist文件中,配置pcl、eigen、opencv、yaml-cpp、openmp库_chennuo0125的博客-CSDN博客

yaml使用总结_测试开发知识积累的博客-CSDN博客 

yaml

1. YAML简介

1.1. 定义规则

YAML是专门用来写配置文件的语言,非常简洁和强大,比 JSON和xml格式要方便很多。

YAML语言(发音 /ˈjæməl/ )的设计目标,就是方便人类读写。它实质上是一种通用的数据串行化格式。它的基本语法规则如下

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略。

YAML支持的数据结构有三种。

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

1.2. 语法

key: value;kv之间有空格 k: v
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
字符串默认不使用引号表示。如果字符串之中包含空格或特殊字符,需要放在引号之中。
单引号和双引号都可以使用,双引号不会对特殊字符转义。
单引号之中如果还有单引号,必须连续使用两个单引号转义。
字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。

 

1.3. 常用解析库

一般常用yaml-cpp和OpenCV进行解析

相比yaml-cpp,OpenCV的优点是可以在YAML文件中存储矩阵,读出来就是cv::Mat格式;缺点是OpenCV要求YAML文件有一个特殊的头,与标准的YAML文件并不兼容。或者也可以理解为OpenCV定义了一种新的YAML格式。

2. 安装yaml-cpp

git clone .git
cd yaml-cpp
mkdir build && cd build
cmake .. && make -j
sudo make install

3. CMakeLists配置

find_package(yaml-cpp REQUIRED)
include_directories(${YAML_CPP_INCLUDE_DIR})
target_link_libraries(node_name yaml-cpp)

4. yaml的解析

4.1. Node

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>()表示将解析的内容转换成 string 类型。
你也可以转换成其它类型。

它是一个模板方法。

4.2. yaml文件的解析

比如这样一个配置文件config.yaml

name: frank
sex: male
age: 18skills: c++: 1java: 1android: 1python: 1
#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;
}

4.3. 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是一个Mapnode["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插入了一个Sequencenode_2.push_back(v);assert(node_2.IsSequence());//当然,node_2仍然是一个Sequenceassert(node_2[0].as<std::string>() == "first item");//对于Sequence类型,你可以使用它的下标来访问//注意这里as<T>是一个模板转换,node_2[0]的type是NodeType::Scalarauto 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");//你可以通过这个指针访问那个nodenode.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 item1: second_item2: third_item3:- 1- 3- 5- 7- 9key: value

4.4. yamlcpp中的迭代

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() 判断迭代器是否结束。

4.5. NodeType类型

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

namespace YAML {struct NodeType {enum value { Undefined, Null, Scalar, Sequence, Map };};
}

对应未定义、空、标量、序列、字典。

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;

上面的代码是为了判断 NodeType。

结果如下:

 Type: 3Type: 2Type: 4

分别对应 Sequence、Scalar、Map。

4.6. yaml-cpp写配置文件(yaml文件的保存与读取)

日常开发中,经常用yaml文件来做配置文件,除了读取配置参数,我们经常需要保存参数,yaml-cpp 自然也提供了相应的功能。

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;//也可以用迭代器访问

参考文献

C++ 解析yaml文件的使用方法_sunlin972913894的博客-CSDN博客_c yaml

在cmakelist文件中,配置pcl、eigen、opencv、yaml-cpp、openmp库_chennuo0125的博客-CSDN博客

yaml使用总结_测试开发知识积累的博客-CSDN博客 

发布评论

评论列表 (0)

  1. 暂无评论