【實習總結】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
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84437.shtml
英文地址,請注明出處:http://en.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的安裝對很多朋友來說可能有點復雜&…