【实习总结】C++ 通过pugi::xml库对xml文件进行操作

目录

相关背景

pugi::xml简概

将配置信息写入xml文件

读取xml文件中的配置信息


相关背景

        当我们需要将某些配置信息写入项目目录下的xml文件,或者再程序启动时,加载项目下已有的的配置信息(.xml),此时,我们可以使用轻量级C++ XML处理库pugi::xml,来对xml文件进行操作。

pugi::xml简概

首先我们通过如下链接,下载pugi::xml源码的压缩包

项目首页 - pugixml:Light-weight, simple and fast XML parser for C++ with XPath support - GitCodehttps://gitcode.com/gh_mirrors/pu/pugixml/?utm_source=artical_gitcode&index=top&type=card&webUrl&isLogin=1解压之后,将源码中的src目录下,三个文件,复制到工程中即可,三个文件如下:

在项目中引用头文件即可正常使用

#include "pugixml.hpp "

常见节点类型

pugi::node_element                               // 普通元素节点 <element>
pugi::node_text                                     // 文本节点
pugi::node_comment                            // 注释节点 <!-- comment -->
pugi::node_declaration                        // XML 声明 <?xml ...?>
pugi::node_cdata                                // CDATA 节点 <![CDATA[...]]>
pugi::node_pi                                     // 处理指令 <?target data?>
prepend_child()                                 // 在 最前面 添加子节点
append_child()                                 //在 最后面 添加子节点 

将配置信息写入xml文件

1、构建存放xml文件的文件路径

CString csXmlFile;
/*获取项目根目录路径*/
/*#define GetProjectRootMgr() ((CEditorApp*)AfxGetApp())->m_prjRootMgr*/
csXmlFile = GetProjectRootMgr().getProjectDir().c_str();
/*拼接xml配置文件名*/
csXmlFile += L"\\BACnetMSTPServerConfig.xml";

这里需要注意的是 GetProjectRootMgr()是我们事先定义好的宏,用来获取项目的根目录,详情如下:

#define GetProjectRootMgr() ((CEditorApp*)AfxGetApp())->m_prjRootMgr

 这个宏定义各部分的作用如下:

  • AfxGetApp() :获取当前MFC应用程序实例

  • (CEditorApp*) :将应用程序实例转换为具体的 CEditorApp 类型

  • ->m_prjRootMgr :访问该应用程序对象的项目根管理器成员变量

2、创建xml文档对象,并尝试加载现有的配置文件

/*创建xml文档对象*/
pugi::xml_document xmlDoc;
/*尝试加载现有的配置文件*/
pugi::xml_parse_result result = xmlDoc.load_file(csXmlFile);

xmlDoc.load_file尝试加载我们所构建的文件路径对应的文件,它的返回值是xml_parse_result,这是pugixml库中用于表示XML解析结果的结构体。

struct xml_parse_result
{xml_parse_status status;    // 解析状态ptrdiff_t offset;          // 错误位置偏移量xml_encoding encoding;     // 文档编码// 转换为bool,检查是否成功operator bool() const;// 获取错误描述const char* description() const;
};

这个结构体的成员含义如下:

1)status(解析状态)

xml_parse_status是一个枚举类型,常用值如下:

状态值含义
status_ok解析成功
status_file_not_found文件未找到
status_io_errorI/O错误
status_out_of_memory内存不足

2)offset(错误位置)

当解析失败时,指示错误发生的字节偏移量,成功时通常为0。

3、进行判断,如果不存在现有的配置文件,则添加xml声明头,并创建根节点

if (result.status == pugi::status_file_not_found) {/*添加声明*/pugi::xml_node declNode = xmlDoc.prepend_child(pugi::node_declaration);declNode.append_attribute(L"version").set_value(L"1.0");declNode.append_attribute(L"encoding").set_value(L"UTF-8");xmlDoc.root().append_child(L"Bacnet_MSTP_Server");xmlDoc.save_file(csXmlFile);result = xmlDoc.load_file(csXmlFile);
}

当配置文件不存在时 :

  • 添加XML声明头: <?xml version="1.0" encoding="UTF-8"?>

  • 创建根节点 <Bacnet_MSTP_Server>

  • 保存文件并重新加载

4、检查xml是否加载成功

if (result.status != pugi::status_ok) {return -1;
}

成功则继续

5、清理和重置配置节点(可根据需求)

	xml_node nodeBACnetMFTP, nodeServerMFTP;nodeBACnetMFTP = xmlDoc.root().child(L"Bacnet_MSTP_Server");nodeBACnetMFTP.remove_attributes();nodeBACnetMFTP.remove_children();nodeBACnetMFTP.append_attribute(L"Enabled").set_value(1);
  • 获取Bacnet_MSTP_Server根节点

  • 清除所有现有属性和子节点

  • 添加 Enabled="1" 属性

效果如下:

6、服务器配置信息保存(添加子节点)

	/*nodeBACnetMFTP在第五步的时候有赋值*/nodeServerMFTP = nodeBACnetMFTP.append_child(L"Server");// 创建子节点而不是属性pugi::xml_node nodeDeviceID = nodeServerMFTP.append_child(L"DeviceID");nodeDeviceID.text().set(m_serverInfo.nDataBit);pugi::xml_node nodeMacAddress = nodeServerMFTP.append_child(L"MacAddress");nodeMacAddress.text().set(m_serverInfo.nMacAdd);pugi::xml_node nodeComType = nodeServerMFTP.append_child(L"ComType");nodeComType.text().set(m_serverInfo.wsConnectType.data());pugi::xml_node nodeBaudRate = nodeServerMFTP.append_child(L"BaudRate");nodeBaudRate.text().set(m_serverInfo.nBaud);pugi::xml_node nodeTimeout = nodeServerMFTP.append_child(L"Timeout");nodeTimeout.text().set(m_serverInfo.nTimeout);pugi::xml_node nodeDesc = nodeServerMFTP.append_child(L"Desc");if (m_serverInfo.bMSTP) {nodeDesc.text().set(L"MSTP Server");}else {nodeDesc.text().set(L"a simple BACnet");}

 效果如下:

7、保存文件

最后,将文件保存

unsigned int nFlag = pugi::format_indent | pugi::format_write_hex_char | pugi::format_save_file_text;
if (!xmlDoc.save_file(csXmlFile, L"\t")) {return -2;
}
return 0;
  • 设置XML格式化标志(缩进、十六进制字符、文本格式)

  • 使用制表符缩进保存文件

  • 保存失败返回 -2 ,成功返回 0

最终结果如下:

读取xml文件中的配置信息

1、构建xml文件路径

与写入xml文件一样,在读取之前需要先构建要读取的xml文件路径

CString csXmlFile; 
csXmlFile = GetProjectRootMgr().getProjectDir().c_str(); 
csXmlFile += L"\\BACnetMSTPServerConfig.xml"; 

这里同样在项目目录下,构建完文件路径之后,与写入是不同的是,我们需要判断是否存在这个配置文件,如果不存在,则不需要读取加载了。

if (!PathFileExists(csXmlFile)) { return -1; 
}

2、加载xml配置文件

如果xml配置文件已经存在,则创建文档对象,并尝试加载

pugi::xml_document xmlDoc; 
pugi::xml_parse_result result = xmlDoc.load_file(csXmlFile, pugi::parse_default | pugi::parse_ws_pcdata); 
if (result.status != pugi::status_ok) { return -2; 
}
  • pugi::parse_default

 默认解析选项 ,包含:

  - parse_cdata - 解析 CDATA 节点
  - parse_escapes - 处理转义字符(如 &lt; , &gt; )
  - parse_wconv_attribute - 属性值的空白字符转换
  - parse_eol - 行尾字符标准化

  • pugi::parse_ws_pcdata

- 保留文本节点中的空白字符

- 默认情况下,pugi::xml 会忽略纯空白的文本节点

- 添加此选项后,空白字符(空格、制表符、换行符)会被保留

3、提取数据

根节点数据

获取根节点

pugi::xml_node nodeBACnet = xmlDoc.root().first_child(); 
if (!nodeBACnet) { return -3; 
}

获取根节点属性

int nEnabled = 0;
m_listObjects.clear();
if (nodeBACnet) { nEnabled = nodeBACnet.attribute(L"Enabled").as_int();

根节点的子节点数据

解析服务器(Server)信息

pugi::xml_node nodeServer = nodeBACnet.child(L"Server"); 
m_serverInfo.wsName = nodeServer.attribute(L"Name").as_string();

当一个节点有很多子节点的话,我们可以通过循环

pugi::xml_node nodeObjects = nodeBACnet.child(L"Objects");
m_nNum = 0;
if (nodeObjects) {for (pugi::xml_node nodeObject : nodeObjects.children(L"Object")) {BACNETSERVER_OBJECT_INFO_T tempObjectInfo;tempObjectInfo.wsObjectName = nodeObject.attribute(L"Name").as_string();tempObjectInfo.wsDesc = nodeObject.attribute(L"Desc").as_string();tempObjectInfo.nType = nodeObject.attribute(L"Type").as_int();tempObjectInfo.nInstance = nodeObject.attribute(L"Instance").as_int();tempObjectInfo.wsAddr = nodeObject.attribute(L"Addr").as_string();tempObjectInfo.nUnits = nodeObject.attribute(L"Units").as_int();pugi::xml_node nodeMultistateText = nodeObject.child(L"MultistateText");if (nodeMultistateText) {for (pugi::xml_node nodeState : nodeMultistateText.children(L"State")){BACNETSERVER_MULTISTATETEXT_INFO_T stateInfo;stateInfo.nNumber = nodeState.attribute(L"Number").as_int();stateInfo.wsText = nodeState.text().as_string();tempObjectInfo.vecMultiStateText.emplace_back(stateInfo);}}m_nNum++;/*读取完一条,存储起来*/m_listObjects.emplace_back(tempObjectInfo);}
}

这里要注意.child()和.children()的区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84437.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux文件回收机制:安全删除文件不怕误删

Linux文件回收机制&#xff1a;安全删除文件不怕误删 文章目录 Linux文件回收机制&#xff1a;安全删除文件不怕误删一、Linux默认没有“回收站”&#xff1f;二、打造你自己的Linux回收站1. 建立回收站目录2. 创建软删除命令remove3. 定时清理回收站4. 替换rm命令5. 完整脚本 …

数据结构排序

目录 1、插入排序 2、希尔排序 3、堆排序 4、直接选择排序 5、快排 6、归并排序 补&#xff1a;计数排序 1、插入排序 void InsertSort(int* arr, int n) {int i 0;for (int i 0; i 1 < n; i){int end i;int tmp arr[end 1];while (end > 0){if (arr[end] &…

Spring声明式事务生效是有条件滴!

在日常工作中&#xff0c;经常使用Transactional 注解进行事务的声明&#xff0c;但如果发现事务未生效&#xff0c;可以从下面几个方面进行排查。 常见失效场景总结 场景原因解决方案内部方法调用绕过了Spring代理注入自身或使用AopContextprivate方法AOP无法增强改为public方…

Code Composer Studio快捷键

文本编辑 编辑、查找、替换功能快捷键 功能快捷键撤销CutZ重做CutY剪切CtrlX复制CtrlC粘贴CtrlV删除Delete全选CtrlA代码块选中AltShiftA查找、替换Ctrl F查找下一个匹配的字符串CtrlK查找上一个匹配的字符串CtrlShiftK查看接口注释&#xff08;文档&#xff09;F2查看函数帮…

从认识AI开始-----生成对抗网络(GAN):通过博弈机制,引导生成

前言 生成对抗网络&#xff08;GAN&#xff09;是lan J. Goodfellow团队在2014年提出的生成架构&#xff0c; 该架构自诞生起&#xff0c;就产生了很多的话题&#xff0c;更是被称为生成对抗网络是“新世纪以来机器学习领域内最有趣的想法”。如今&#xff0c;基于生成对抗网络…

限流算法java实现

参考教程&#xff1a;2小时吃透4种分布式限流算法 1.计数器限流 public class CounterLimiter {// 开始时间private static long startTime System.currentTimeMillis();// 时间间隔&#xff0c;单位为msprivate long interval 1000L;// 限制访问次数private int limitCount…

Maven 构建性能优化深度剖析:原理、策略与实践

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

JS手写代码篇---手写深拷贝

17、深拷贝 深拷贝与浅拷贝最大的不同就是对象的属性是嵌套对象&#xff0c;会新建一个对象 步骤&#xff1a; 判断是否为对象判断是否为i数组或者对象&#xff0c;给新的有个容器遍历循环&#xff0c;如果是对象要遍历循环&#xff0c;采用递归 function deepCopy(obj){// …

【react实战】如何实现监听窗口大小变化

在日常开发场景中&#xff0c;监听窗口变化是一个比较常见又很重要的业务功能&#xff0c;其实实现起来也很简单&#xff0c;今天就来记录一下具体的实现以及注意事项。 实现思路 在 React 中&#xff0c;可以通过监听 window 的 resize 事件来检测可视区域&#xff08;viewp…

AVCap视频处理成帧和音频脚本

###############处理原视频&#xff0c;使其格式和原数据一样 import os import cv2 import subprocess import json from PIL import Image from pydub import AudioSegmentimport sys import shutil # &#x1f539; 第一步&#xff1a;强制检测并设置FFmpeg路径 &#x1f5…

数据冗余对企业运营的隐性成本

从客户管理到供应链优化&#xff0c;再到市场分析&#xff0c;数据无处不在&#xff0c;数据已成为企业运营的核心驱动力。然而&#xff0c;随着企业IT系统的多样化和数据量的激增&#xff0c;数据冗余&#xff08;Data Redundancy&#xff09;问题逐渐浮出水面&#xff0c;成为…

HTML原生日期插件增加周次显示

<div id="app" class="box box-info" style="border-top-color:white;"><!-- // 日期部分 --><div class="date-picker-container" style="position: relative; max-width: 200px;"><!-- 日期输入框 -…

渗透测试PortSwigger Labs:遭遇html编码和转义符的反射型XSS

1 处是我们输入的标签被服务器 html 编码后返回&#xff0c;被浏览器当作字符串显示出来&#xff0c;无法执行 javascript 2 处是唯一能控制的地方&#xff0c;正好在script标签范围内&#xff0c;可以尝试构造 依然存在转移单引号&#xff0c;我们输入转义符\让服务器添加的转…

Ansible 错误处理:确保高效自动化

当 Ansible 收到命令的非零返回码或模块故障时,默认情况下,它会停止在该主机上的执行,并在其他主机上继续执行。但是,在某些情况下,您可能需要不同的行为。有时非零返回码表示成功。有时您希望一台主机上的故障导致所有主机上的执行停止。Ansible 提供了处理这些情况的工具…

【无标题】NP完全问题的拓扑对偶统一解法 ——四色问题到P=NP的普适框架

NP完全问题的拓扑对偶统一解法 ——四色问题到PNP的普适框架 **摘要** 本文提出基于**拓扑膨胀-收缩对偶性**的计算理论框架&#xff0c;突破传统NP完全性理论局限。通过将离散组合问题转化为连续几何问题&#xff0c;并引入规范场量子求解机制&#xff0c;实现四色问题、子…

【Zephyr 系列 19】打造 BLE 模块完整 SDK:AT 命令系统 + 状态机 + NVS + OTA 一体化构建

🧠关键词:Zephyr、BLE 模块、SDK 构建、AT 命令框架、有限状态机、Flash 配置、MCUboot OTA 📌面向读者:希望将 BLE 项目标准化、封装化、支持量产使用的开发团队与架构师 📊预计字数:5500+ 字 🧭 背景与目标 在完成多个 BLE 功能模块后,一个企业级产品往往需要:…

机器学习核心概念速览

机器学习基本概念 有监督学习分类、回归无监督学习聚类、降维 一维数组 import numpy as np data np.array([1,2,3,4,5]) print(data) print(data.shape) print(len(data.shape))[1 2 3 4 5] (5,) 1二维数组 data2 np.array([[1,2,3],[4,5,6]]) print(data2) print(data2…

在 Java 中实现一个标准 Service 接口,并通过配置动态选择具体实现类供 Controller 调用

在 Java 中实现一个标准 Service 接口&#xff0c;并通过配置动态选择具体实现类供 Controller 调用&#xff0c;是解耦和灵活扩展的常见设计模式。 需求分析 当你需要开发一个需要灵活切换业务实现的系统&#xff0c;比如不同环境使用不同策略&#xff08;如测试环境用Mock实…

input+disabled/readonly问题

背景&#xff1a; vue2elementui <el-input v-model"inputForm.projectName" class"input-font" :disabled"projectDisabled" placeholder"请选择" :readonly"isReadonly"><el-button slot"append"…

Office2019下载安装教程(2025最新永久方法)(附安装包)

文章目录 Office2019安装包下载Office2019一键安装步骤&#xff08;超详细&#xff01;&#xff09; 大家好&#xff01;今天给大家带来一篇超实用的Office2019专业版安装教程&#xff01;作为日常办公和学习的必备软件&#xff0c;Office的安装对很多朋友来说可能有点复杂&…