当前位置: 首页 > news >正文

如何使用CAPL解析YAML文件?

  • 🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用
  • 🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】
  • 🍅 玩转CANoe,博客目录大全,点击跳转👉

📘前言

  • 🍅 在基于CAPL编写测试用例时,时常会用到配置文件,虽然CAPL内置了对INI配置文件的读写函数,不过INI配置文件比较简单,无法记录较为复杂的数据结构,而YAML配置文件 是一种人性化的数据序列化格式,功能强大,适用于所有编程语言,但是CAPL语言并没有函数支持解析YAML文件,本文就基于C++的开源库yaml-cpp创建一个动态链接库,以实现CAPLYAML文件的支持。

请添加图片描述

目录

  • 📘前言
  • 📙 1、YAML文件语法简介
  • 📙 2、CAPL 示例
    • 📙 2.1、读取标量(Yaml_GetScalarValue)
    • 📙 2.2、读取列表(Yaml_GetListValues)
    • 📙 2.3、读取字典(Yaml_GetMapValue)
  • 📙 3 编译和应用yaml-cpp库
    • 📙 3.1 编译
    • 📙 3.2 配置
  • 📙 4、示例工程和源码获取

📙 1、YAML文件语法简介

YAML (YAML Ain't Markup Language) 是一种人类友好的数据序列化标准,适用于所有编程语言。它具有以下特点:

1.1 基本结构:

  • 大小写敏感。
  • 使用缩进表示层级关系(通常2个空格)(YAML对缩进非常敏感,必须使用空格(不能使用制表符),且同一层级元素必须对齐
  • 使用-表示列表项
  • 使用key: value表示键值对

1.2 主要特性:

支持三种基本数据结构:

  • 标量(字符串、数字、布尔值等)
  • 序列(数组/列表)
  • 映射(字典/键值对)

1.3 示例结构

# 注释以#开头
简单键值:
  key1: value1
  key2: value2

列表示例:
  - 项目1
  - 项目2
  - 项目3

嵌套结构:
  parent:
    child1: 值1
    child2: 值2
    children:
      - 子项1
      - 子项2

多行字符串: |
  这是多行
  文本内容

1.4 数据类型支持:

  • 字符串(默认不需要引号)
  • 数字(整数、浮点数)
  • 布尔值(true/false)
  • null(用~或null表示)
  • 时间日期(ISO8601格式)

1.5 优势:

  • 可读性强,结构清晰
  • 适合配置文件和数据交换
  • 支持跨平台和跨语言
  • 比JSON更灵活,比XML更简洁

1.6 典型应用场景:

  • 配置文件(如Docker Compose、Kubernetes)
  • 数据序列化
  • 测试用例定义
  • CI/CD管道配置

📙 2、CAPL 示例

如下图所示,基于C++开源库yaml-cpp封装的可以在CAPL中使用的yaml_demo.dll,主要函数接口:

  • long Yaml_GetScalarValue(const char* filename, const char* key, char* returnValue, long returnValueSize, char* error_info, long error_info_size) :读取yaml文件中的标量

    • filename:yaml文件路径
    • key:读取的键值对的key ,可以通过settings.debug的方式读取嵌套的内层的参数
    • returnValue:无论是布尔/数值/字符串类型变量,都以字符串的方式返回
    • returnValueSize:returnValue参数的最大长度
    • error_info:如果解析yaml文件失败,失败信息通过该参数返回
    • error_info_size::error_info参数的最大长度
    • 返回值:读取成功,返回值为1,否则返回值为-1
  • long Yaml_GetListValues(const char* filename, const char* key, char returnValues[][1024], long maxReturnValues, char* error_info, long error_info_size):读取yaml文件中的列表

    • returnValues:二维字符串数组,yaml文件中的列表参数无论什么类型都转为字符串类型返回,注意这里以C语言类型的数组传参,要求CAPL语言中定义的接收数组的字节数也必须是1024
    • maxReturnValues:允许返回的列表的最大元素数
    • 返回值:读取成功,返回值为读取的列表的元素个数,否则返回值为-1
  • long Yaml_GetMapValue(const char* filename, const char* key, char* returnValue, long returnValueSize, char* error_info, long error_info_size):读取yaml文件中的字典,参数定义和GetScalarValue函数一致,唯一不同的是GetMapValue函数读取的字典数据以json字符串的方式返回。

     *说明:这个dll只实现了读取yaml文件,没有实现写入yaml文件。*
    

在这里插入图片描述

  • CANoe Demo 工程下有个Config.yaml文件,内容如下:
# config.yaml
name: Example Project
version: 1.0.0
dependencies: #yaml风格的列表
  - library1
  - library2
  - library3
system: [linux,window,mac] #json风格的列表

settings:
  debug: true
  max_connections: 100
  timeout: 30.5
  description:  This is a sample project
  中文: 支持中文
  颜色: # 中文参数
  - 红色
  - 绿色
  - 蓝色

nested_structure:
  level1:
    level2:
      level3: deep_value
list_of_maps:
  - name: item1
    value: 10
  - name: item2
    value: 20
  - name: item3
    value: 30
mixed_list:
  - string_value
  - 42
  - 3.14
  - true
  - 
nested_key: nested_value
empty_value: null

📙 2.1、读取标量(Yaml_GetScalarValue)

  • 如下CAPL脚本,分多种情况读取标量参数
/*@!Encoding:65001*/
includes
{
    #pragma library("yaml_demo.dll") // X86 平台
}
variables
{
    char filename[100] = "node\\Config.yaml";
    char returnValue[4096];
    char List_returnValue[100][1024];
    char error_info[256];
    long result;  
}
on key 'e'
{
  //获取普通的标量
  result =  Yaml_GetScalarValue(filename,"name",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("name = %s",returnValue); 
  //获取字典的一个元素,值为布尔类型(转为字符串输出)
  result =  Yaml_GetScalarValue(filename,"settings.debug",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("settings.debug = %s",returnValue); 
   //获取字典的一个标量元素,值为字浮点数类型(转为字符串输出)
  result =  Yaml_GetScalarValue(filename,"settings.timeout",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("settings.timeout = %s",returnValue); 
  //获取字典的一个标量元素,值为字符串类型(转为字符串输出)
  result =  Yaml_GetScalarValue(filename,"settings.description",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("settings.description = %s",returnValue); 
  //获取字典嵌套的一个标量元素
  result =  Yaml_GetScalarValue(filename,"nested_structure.level1.level2.level3",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("nested_structure.level1.level2.level3 = %s",returnValue); 
   //获取字典嵌套的一个标量元素(中文字符)
  result =  Yaml_GetScalarValue(filename,"settings.中文",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("settings.中文 = %s",returnValue); 
  
  //获取字典嵌套的一个列表元素的元素
  result =  Yaml_GetScalarValue(filename,"list_of_maps.name",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("list_of_maps.name = %s",returnValue); 
}
  • 测试结果如下:
Program / Model	name = Example Project
Program / Model	settings.debug = true
Program / Model	settings.timeout = 30.5
Program / Model	settings.description = This is a sample project
Program / Model	nested_structure.level1.level2.level3 = deep_value
Program / Model	settings.中文 = 支持中文
Program / Model	list_of_maps.name = item1

📙 2.2、读取列表(Yaml_GetListValues)

  • 读取列表的示例CAPL脚本如下:
on key 'r'
{
  long i;
  //获取一个列表
  result =  Yaml_GetListValues(filename,"dependencies",List_returnValue,elcount(List_returnValue),error_info,elcount(error_info));
  for(i =0;i<result;i++)
    write("dependencies[%d] = %s",i,List_returnValue[i]);
  
    //获取一个列表(json风格)
  result =  Yaml_GetListValues(filename,"system",List_returnValue,elcount(List_returnValue),error_info,elcount(error_info));
  for(i =0;i<result;i++)
    write("system[%d] = %s",i,List_returnValue[i]);
  
  //获取字典的一个列表元素,且支持中文
  result =  Yaml_GetListValues(filename,"settings.颜色",List_returnValue,elcount(List_returnValue),error_info,elcount(error_info));
  for(i =0;i<result;i++)
  write("settings.颜色[%d] = %s",i,List_returnValue[i]);
  
  //获取字典的一个列表元素,列表嵌套字典类型
  result =  Yaml_GetListValues(filename,"list_of_maps",List_returnValue,elcount(List_returnValue),error_info,elcount(error_info));
  for(i =0;i<result;i++)
  write("list_of_maps[%d] = %s",i,List_returnValue[i]);
}
  • 测试结果如下:
Program / Model	dependencies[0] = library1
Program / Model	dependencies[1] = library2
Program / Model	dependencies[2] = library3
Program / Model	system[0] = linux
Program / Model	system[1] = window
Program / Model	system[2] = mac
Program / Model	settings.颜色[0] = 红色
Program / Model	settings.颜色[1] = 绿色
Program / Model	settings.颜色[2] = 蓝色
Program / Model	list_of_maps[0] = {"name":"item1","value":"10"}
Program / Model	list_of_maps[1] = {"name":"item2","value":"20"}
Program / Model	list_of_maps[2] = {"name":"item3","value":"30"}

📙 2.3、读取字典(Yaml_GetMapValue)

  • 读取字典的示例CAPL脚本如下:
on key 'y'
{
  long i;
  //获取一个字典,以json字符串的方式返回
  result =  Yaml_GetMapValue(filename,"settings",returnValue,elcount(returnValue),error_info,elcount(error_info));
  write("result = %d ,returnValue = %s",result,returnValue);
}
  • 测试结果如下:
Program / Model	result = 1 ,returnValue = {"debug":"true","max_connections":"100","timeout":"30.5","description":"This is a sample project","中文":"支持中文","颜色":["红色","绿色","蓝色"]}

📙 3 编译和应用yaml-cpp库

📙 3.1 编译

编译C++库的一般步骤
1,下载开源库

git clone https://github.com/jbeder/yaml-cpp.git 

如果上述下载失败或者没有安装git,可以选择手动下载 yaml-cpp 中国镜像地址

2、下载cmake

Cmake 下载官网,安装包类型:

  • Windows: .msi 或 .zip 格式
  • macOS: .dmg 或 .tar.gz 格式
  • Linux: 源码或特定发行版的二进制包

对于 Windows 用户,建议下载 .msi 安装包(如 cmake-3.28.1-windows-x86_64.msi),安装时勾选 “Add CMake to system PATH” 以便命令行直接使用。

3,编译yaml-cpp

这里要注意编译的平台和类型,比如我这里在使用yaml-cpp编译的库创建动态库时的配置时X86平台,配置是Debug类型,所以下面的编译参数就是-A Win32 -DCMAKE_BUILD_TYPE=Debug,
编译完成后,会在.\build\Debug路径下生成一个yaml-cppd.lib文件,这就是编译的库文件

cd yaml-cpp
mkdir build
cd build
cmake .. -A Win32 -DCMAKE_BUILD_TYPE=Debug
cmake --build . --config Debug

📙 3.2 配置

在Visual studio中手动配置yaml-cppd.lib文件的步骤如下

1、项目属性 → C/C++ → 常规 → 附加包含目录:

path\to\yaml-cpp\include

2、项目属性 → 链接器 → 常规 → 附加库目录:

path\to\yaml-cpp\build\Debug

3、项目属性 → 链接器 → 输入 → 附加依赖项:

yaml-cppd.lib

4、示例代码

#define YAML_CPP_STATIC_DEFINE  // 如果使用静态库
#include <yaml-cpp/yaml.h>

int main() {
    YAML::Node config = YAML::LoadFile("config.yaml");
    std::string name = config["name"].as<std::string>();
    return 0;
}

5、常见问题解决

编译错误:

  • 确保 Visual Studio 工具链选择的是 x86
  • 清理 build 目录重新生成

链接错误

  • 检查是否正确定义了 YAML_CPP_STATIC_DEFINE
  • 确保 Debug/Release 配置匹配

📙 4、示例工程和源码获取

23

  • 🍅 基于CAPL语法生成的解析YAML配置文件的DLL文件(CANoe工程文件)

  • 🍅 基于CAPL语法生成的解析YAML配置文件DLL(C++源码以及CANoe工程Demo)


    7
  • 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!

  • 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
    18

相关文章:

  • Python爬虫第13节-解析库pyquery 的使用
  • C++ | 时间日期
  • WEB 前端学 JAVA(一)
  • Qwen2.5-7B-Instruct FastApi 部署调用教程
  • YOLO学习笔记 | YOLOv8 全流程训练步骤详解(2025年4月更新)
  • 知行之桥2025版账号密码修改和重置指南
  • .NET WPF 可视化树(Visual Tree)
  • MCP工具的配置文件格式是怎么样的?MCP教程平台推荐
  • RVOS-3.实现内存管理
  • Compose 适配 - 响应式排版 自适应布局
  • 基于SpringBoot的智慧社区管理系统(源码+数据库)
  • 蓝桥杯单片机刷题——通过按键触发串口传输电压值
  • 这种情况是应为VScode的版本太新了,更新到1.86版本后要求远程连接服务器的内核版本不符合条件
  • 【力扣hot100题】(075)数据流的中位数
  • 2025年3月GESPC++三级考级真题——2025
  • Elasticsearch 系列专题 - 第六篇:高级功能与生态系统
  • P8627 [蓝桥杯 2015 省 A] 饮料换购
  • Linux用户切换命令区别详解
  • 【JDBC-54】JDBC:Java数据库连接的桥梁与核心特性解析
  • 进度计划频繁变更,如何稳定推进
  • 做网站管理好吗/品牌广告策划方案
  • 深圳做h5网站设计/企业营销策划是做什么的
  • 烟台赶集网网站建设/优化排名软件
  • 做网站投资要多少钱/成都关键词优化服务
  • 党建设计/大金seo
  • 以太坊网站开发/网络营销品牌案例