XML读写

XML初识

一、背景

自己写的从网页获取内容的小工具,那个网页是涉及到一个模拟器的启动。启动模拟器需要等五分钟才能读取数据。如果每次读都启动模拟器等待,等待时间较久,我在想应该在硬盘中将已经启动过模拟器的标志位写到xml文件中。所以就涉及到了xml。

二、关于XML

2.1 查找资料

概念
TinyXML是一个开源的解析XML的解析库。解析库的模型通过解析XML文件,在内存中生成DOM模型,使得可以方便的遍历XML。

官方下载地址:https://sourceforge.net/projects/tinyxml/?source=directory

github下载地址:https://github.com/leethomason/tinyxml2

模型
主要有两大模型:SAX和DOM。

SAX:基于事件的模型,基本工作流程是分析XML文档,当发现了一个新的元素时,产生一个对应事件,并调用相应的用户处理函数。这种方式占用内存少,速度快,但用户程序相应得会比较复杂;
DOM:文档对象模型,分析整个XML文档,将整个文档分成多个元素(如书、章、节、段等),在内存中形成对应的树结构。同时,向用户提供一系列的接口来访问和编辑树结构。这种方式占用内存大,速度往往慢于SAX,但可以给用户提供一个面向对象的访问接口,对用户更为友好;

参考文章:c++ tinyXml介绍

2.2 下载xml库

使用的是tinyXml2的源码

在clion上实现xml读写,将tinyxml2-10.0.0版本tinyXML源码放在路径下,cmakelist指向tinyXML路径

2.3 编写代码

xml读写代码

#include <iostream>
#include <string>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include "tinyxml2.h"using namespace std;
using namespace tinyxml2;std::string GetCurrentPath()
{char cwd[1024];if (getcwd(cwd, sizeof(cwd)) != nullptr) {std::cout << "Current working directory: " << cwd << std::endl;} else {std::cerr << "Error retrieving current directory!" << std::endl;}return cwd;
}std::string GetCurrentTime()
{std::time_t now = std::time(nullptr);std::tm* ltm = std::localtime(&now);std::stringstream ss;ss << std::put_time(ltm, "%Y-%m-%d %H:%M:%S");return ss.str();
}std::string GetXMLFilePath()
{std::string currentPath = GetCurrentPath();std::string xmlFilePath = currentPath.substr(0, currentPath.find_last_of("/") + 1) + "data/favorite_place.xml";return xmlFilePath;
}bool ReadXmlFile(std::string xmlPath)
{XMLDocument xml_doc;if (xml_doc.LoadFile(xmlPath.c_str()) != XML_SUCCESS) {return false;}XMLElement* xml_root = xml_doc.RootElement();if (NULL == xml_root) {return false;}XMLNode* p_data_type_node = xml_root->FirstChild();while (p_data_type_node) {XMLElement* p_data_level_element = p_data_type_node->ToElement();const XMLAttribute* pAttr = p_data_level_element->FirstAttribute();     //不知道有啥用;2024年6月1日11:18:31更新 用处就是获取attributestd::string str_time = p_data_level_element->GetText();std::cout << "str_time: " << str_time << std::endl;p_data_type_node = p_data_type_node->NextSibling();}return true;
}bool ReadXMLWayTwo(std::string xmlPath)
{XMLDocument doc;if (doc.LoadFile(xmlPath.c_str()) != XML_SUCCESS) {cout << "Error parsing XML file" << endl;return false;}XMLElement* root = doc.RootElement();if (root == nullptr) {cout << "Error: XML is empty or has no root element!" << endl;return false;}// 遍历子元素for (XMLElement* child = root->FirstChildElement(); child != nullptr; child = child->NextSiblingElement()) {const char* value = child->GetText();if (value == nullptr) {cout << "Error: XML element has no text" << endl;} else {cout << child->Name() << ": " << value << endl;}}return true;
}/** <?xml version="1.0"?>* <root>* <element attribute="value">Some text</element>* </root>*/
bool WriteXML(std::string xmlPath)
{XMLDocument doc;doc.InsertEndChild(doc.NewDeclaration());XMLElement* root = doc.NewElement("root");doc.InsertEndChild(root);// 创建一个元素并添加到根元素XMLElement* element = doc.NewElement("element");element->SetText(GetCurrentTime().c_str());root->InsertEndChild(element);// 创建属性
//    XMLAttribute* attr = doc.NewAttribute("attribute", "value");
//    element->InsertAttribute(attr);// 保存到文件XMLError error = doc.SaveFile(xmlPath.c_str());if (error != XML_SUCCESS) {std::cout << "Error saving XML file" << std::endl;return 1;}return true;}int main()
{std::string xmlPath = GetXMLFilePath();WriteXML(xmlPath);ReadXmlFile(xmlPath);ReadXMLWayTwo(xmlPath);return 0;
}

cmakelist.txt

cmake_minimum_required(VERSION 3.16.5)message("this is cmakelist log")
message(${CMAKE_CURRENT_SOURCE_DIR})get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
message(${ProjectId})
message(${ProjectId})
message(NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
message(${ProjectId})
project(${ProjectId} CXX)#添加宏定义Debug为CMAKE_BUILD_TYPE
SET(CMAKE_BUILD_TYPE "Debug")set(CMAKE_CXX_STANDARD 17)if (CMAKE_BUILD_TYPE STREQUAL Debug)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_DEBUG")
else ()set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_DEBUG")
endif ()#添加头文件
#例如:include_directories(/usr/include/abc /usr/include/xxx)
#是将“/usr/include/abc”和“/usr/include/xxx”这两个目录添加至编译器的头文件搜索目录(两个目录用空格分隔)。
include_directories(../3rd/tinyxml2-10.0.0)
include_directories(./include/)aux_source_directory(../3rd/tinyxml2-10.0.0 tinyxmlSrc)
aux_source_directory(./src Src)#通过编译源文件来创建一个可执行文件,其中,name是生成的可执行文件的名称,source是创建可执行文件所需要的源文件。
#源文件可以使用aux_source_directory指令返回的变量(将源文件保存在这个变量中),也可以是指定的.cpp文件(注意路径)。
add_executable(${ProjectId}${Src}${tinyxmlSrc}main.cpp)

打印信息

str_time: 2024-05-31 10:11:43
element: 2024-05-31 10:11:43

2.4 看b站使用tinyXML

其实在写上面的代码的饿时候,参考了cityView的代码,但是cityView的代码用到的代码中是TiXmlDocument的写法,我百度了发现好像他用的是tinyXML,而我用的是TinyXML2,我尝试去软件库查tinyXML,但是查到的还是TinyXML2,感觉还是要哔哩哔哩找个视频看下。

2.4.1

看哔哩哔哩看到一个网址,哔哩哔哩视频网址

https://sourceforge.net/projects/tinyxml/files/latest/download

实现读XML方法

xml文件格式

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://xxx.com"><str id="001"><str-test>2024-06-01 09:21:32</str-test><str-test>111</str-test><str-test>222</str-test></str>
</root>

代码如下:

void TinyXMLRead()
{TiXmlDocument* pDoc = new TiXmlDocument();pDoc->LoadFile("/data2/z30031397/myProjTest2/test_xml/data/testTinyXml.xml");TiXmlElement* pRoot = pDoc->RootElement();printf("%s\n", pRoot->Value());TiXmlElement* str = pRoot->FirstChildElement("str");printf("%s\n", str->Value());printf("%s\n", str->Attribute("id"));TiXmlElement* strTest = str->FirstChildElement("str-test");while(strTest){printf("%s\n", strTest->GetText());strTest = strTest->NextSiblingElement("str-test");}delete pDoc;
}

2.5 看b站使用tinyXML2

b站视频网址

up主csdn帖子C++调用tinyxml2读写xml

代码

using namespace std;
using namespace tinyxml2;void createXml()
{//------------//声明要创建的xml文件//------------tinyxml2::XMLDocument xml;tinyxml2::XMLDeclaration* declaration = xml.NewDeclaration();xml.InsertFirstChild(declaration);//------------//创建根节点//------------tinyxml2::XMLElement* rootNode = xml.NewElement("computer");xml.InsertEndChild(rootNode);//------------//创建子节点//------------tinyxml2::XMLElement* root_1_NodeComputerMonitor = xml.NewElement("ComputerMonitor");tinyxml2::XMLElement* root_1_NodeKeyboard = xml.NewElement("Keyboard");tinyxml2::XMLElement* root_1_CPU = xml.NewElement("CPU");//------------//给Monitor子节点增加内容//------------tinyxml2::XMLText* text_root_1_NodeComputerMonitor = xml.NewText("SAMSUNG");root_1_NodeComputerMonitor->InsertFirstChild(text_root_1_NodeComputerMonitor);//------------//给Keyboard子节点增加子节点//------------tinyxml2::XMLElement* root_2_NodeKeyboardAttribute = xml.NewElement("KeyboardAttribute");//------------//给Keyboard子节点的子节点KeyboardAttribute增加内容//------------tinyxml2::XMLText* text_root_2_NodeKeyboardAttribute = xml.NewText("cherry Mechanical Keyboard");root_2_NodeKeyboardAttribute->InsertFirstChild(text_root_2_NodeKeyboardAttribute);//------------//给Keyboard子节点的子节点KeyboardAttribute插入root_1_NodeKeyboard//------------root_1_NodeKeyboard->InsertEndChild(root_2_NodeKeyboardAttribute);//------------//给CPU子节点增加内容//------------tinyxml2::XMLText* text_root_1_root_1_CPU = xml.NewText("intel");root_1_CPU->InsertFirstChild(text_root_1_root_1_CPU);//------------//给Monitor和CPU子节点增加属性//------------root_1_NodeComputerMonitor->SetAttribute("size", "15");root_1_CPU->SetAttribute("series", "XEON");//------------//构建xml树,根节点的下的子节点树//------------rootNode->InsertEndChild(root_1_NodeComputerMonitor);//childNodeStu是root的子节点rootNode->InsertEndChild(root_1_NodeKeyboard);rootNode->InsertEndChild(root_1_CPU);//------------//将xml保存到当前项目中//------------xml.SaveFile("computer.xml");
}void deCodeXml()
{//------------//声明//------------tinyxml2::XMLDocument xml;//------------//导入xml文件//------------if (xml.LoadFile("computer.xml") != XML_SUCCESS){return;}//------------//找到导入的xml的根节点//------------tinyxml2::XMLElement* rootNode = xml.RootElement();if (rootNode == NULL) {return;}//------------//读取第一层子节点信息并且打印在控制台上//------------tinyxml2::XMLElement* root_1_NodeComputerMonitor = rootNode->FirstChildElement("ComputerMonitor");std::string text_root_1_NodeComputerMonitor = root_1_NodeComputerMonitor->GetText();cout << "text_root_1_NodeComputerMonitor = " << text_root_1_NodeComputerMonitor.c_str()<<endl;//------------//读取第二层子节点信息并且打印在控制台上//------------tinyxml2::XMLElement* root_1_NodeKeyboard = rootNode->FirstChildElement("Keyboard");tinyxml2::XMLElement* root_2_NodeKeyboardAttribute = root_1_NodeKeyboard->FirstChildElement("KeyboardAttribute");std::string text_root_2_NodeKeyboardAttribute = root_2_NodeKeyboardAttribute->GetText();cout << "text_root_2_NodeKeyboardAttribute = " << text_root_2_NodeKeyboardAttribute.c_str() << endl;
}int main()
{cout << "----------------------begin create xml-----------------------" << endl;createXml();cout << "----------------------finished create xml--------------------" << endl;cout << "-----------------------begin read xml------------------------" << endl;deCodeXml();cout << "-----------------------finished read xml---------------------" << endl;return 0;
}

生成的xml文件形式:

<?xml version="1.0" encoding="UTF-8"?>
<computer><ComputerMonitor size="15">SAMSUNG</ComputerMonitor><Keyboard><KeyboardAttribute>cherry Mechanical Keyboard</KeyboardAttribute></Keyboard><CPU series="XEON">intel</CPU>
</computer>

感觉看了这个,感觉清楚多了,好像感觉基本理解xml了

然后刚才我还在纠结xml.SaveFile(“computer.xml”);是将文件保存到哪里了,还百度了一下,xml.Save(“configure.xml”)与xml.Save(Filename)的区别。解释是:前者xml文件的搜索路径默认是:进程路径,如果进程路径改变(比如不在exe路径运行,换一个路径运行),就会出问题。

然后我还是没搞懂,最后在cmake-build-debug中找到了computer.xml文件。所以这种写法的文件路径是可执行文件的路径。

2.6 照着上述代码写了自己需要的代码

代码如下

bool ReadXmlFile(std::string xmlPath, std::string &time)
{XMLDocument xml_doc;if (xml_doc.LoadFile(xmlPath.c_str()) != XML_SUCCESS) {return false;}XMLElement* xml_root = xml_doc.RootElement();if (NULL == xml_root) {return false;}XMLElement* pRecordTime = xml_root->FirstChildElement("recordTime");XMLElement* pLastTime = pRecordTime->FirstChildElement("lastTime");std::string lastTime = pLastTime->GetText();std::cout << "lastTime:  " << lastTime << std::endl;return true;
}bool WriteXML(std::string xmlPath, std::string time)
{XMLDocument doc;doc.InsertEndChild(doc.NewDeclaration());XMLElement* root = doc.NewElement("root");// 创建一个元素并添加到根元素XMLElement* recordNode = doc.NewElement("recordTime");XMLElement* lastTimeNode = doc.NewElement("lastTime");XMLText* text_time = doc.NewText(time.c_str());lastTimeNode->InsertEndChild(text_time);recordNode->InsertEndChild(lastTimeNode);root->InsertEndChild(recordNode);doc.InsertEndChild(root);// 保存到文件XMLError error = doc.SaveFile(xmlPath.c_str());if (error != XML_SUCCESS) {std::cout << "Error saving XML file" << std::endl;return false;}return true;
}std::string GetXMLFilePath()
{std::string currentPath = GetCurrentPath();std::string xmlFilePath = currentPath.substr(0, currentPath.find_last_of("/") + 1) + "data/test.xml";return xmlFilePath;
}int main()
{std::string xmlPath = GetXMLFilePath();WriteXML(xmlPath, GetCurrentTime());std::string time = "1900-1-1 00:00:00";xmlPath = GetXMLFilePath();ReadXmlFile(xmlPath, time);return 0;
}

生成xml文件形式:

<?xml version="1.0" encoding="UTF-8"?>
<root><recordTime><lastTime>2024-06-01 15:45:18</lastTime></recordTime>
</root>

然后程序一直有问题,readXml的时候读取失败,我按重点放在了InsertEndChild和InsertFirstChild上,但是实际上最后一点一点增加xml内容,最后定位出是 XMLElement* lastTimeNode = doc.NewElement(“last time”);这一行,XMLElement不能是带空格的两个单词。晕!

三、其他文章

https://blog.csdn.net/anwh9295/article/details/127023055

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

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

相关文章

【机器学习】Qwen1.5-14B-Chat大模型训练与推理实战

目录 一、引言 二、模型简介 2.1 Qwen1.5 模型概述 2.2 Qwen1.5 模型架构 三、训练与推理 3.1 Qwen1.5 模型训练 3.2 Qwen1.5 模型推理 四、总结 一、引言 Qwen是阿里巴巴集团Qwen团队的大语言模型和多模态大模型系列。现在&#xff0c;大语言模型已升级到Qwen1.5&…

使用 Scapy 库编写 ICMP 重定向攻击脚本

一、介绍 ICMP重定向攻击&#xff08;ICMP Redirect Attack&#xff09;是一种网络攻击&#xff0c;攻击者通过发送伪造的ICMP重定向消息&#xff0c;诱使目标主机更新其路由表&#xff0c;以便将数据包发送到攻击者控制的路由器或其他不可信任的设备上。该攻击利用了ICMP协议…

springboot配置集成RedisTemplate和Redisson,使用分布式锁案例

文章要点 自定义配置属性类集成配置RedisTemplate集成配置分布式锁Redisson使用分布式锁简单实现超卖方案 1. 项目结构 2. 集成RedisTemplate和Redisson 添加依赖 依赖的版本与继承的spring-boot-starter-parent工程相对应&#xff0c;可写可不写 <!--spring data redis…

Spring boot 集成mybatis-plus

Spring boot 集成mybatis-plus 背景 Spring boot集成mybatis后&#xff0c;我们可以使用mybatis来操作数据。然后&#xff0c;我们还是需要写许多重复的代码和sql语句&#xff0c;比如增删改查。这时候&#xff0c;我们就可以使用 mybatis-plus了&#xff0c;它可以极大解放我…

沐风老师3DMAX顶点切线控制插件VertexTangants安装使用方法

3DMAX顶点切线控制插件VertexTangants安装使用方法 3DMAX顶点切线控制插件VertexTangants&#xff0c;用于轻松控制图形顶点切线的工具。 【主要功能】 -脚本具有获取选定顶点的自动检测功能&#xff0c;您可以随时使用“获取按钮”获取选定顶点。 -有一个用于激活撤消的ON按…

项目资源管理

目录 1.概述 2.六个过程 2.1. 规划资源管理 2.2. 估算活动资源 2.3. 获取资源 2.4. 建设团队 2.5. 管理团队 2.6. 控制资源 3.应用场景 3.1.十个应用场景 3.2.软件开发项目 3.2.1. 资源规划 3.2.2. 资源分配 3.2.3. 资源获取 3.2.4. 资源优化 3.2.5. 资源监控与…

如何在外网http访问内网邮件server?

不少公司选择用winmail搭建部署内部邮箱服务器&#xff0c;对于邮件管理员&#xff0c;不但需要在局域网内&#xff0c;常常需要在外网也能访问到邮箱服务管理。winmail本身系统功能可以开启http访问管理&#xff0c;但当需要在外网http访问内网邮箱服务时&#xff0c;需要用到…

vue3通过Vite实现工程化

1. vue3简介 Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;Vue 都可以胜任。官网为:Vue.js - 渐进…

在python中连接了数据库后想要在python中通过图形化界面显示数据库的查询结果,请问怎么实现比较好? /ttk库的treeview的使用

在Python中&#xff0c;你可以使用图形用户界面&#xff08;GUI&#xff09;库来显示数据库的查询结果。常见的GUI库包括Tkinter&#xff08;Python自带&#xff09;、PyQt、wxPython等。以下是一个使用Tkinter库来显示数据库查询结果的简单示例。 首先&#xff0c;你需要确保…

Web学习篇(二)

命令执行漏洞 一、常用的函数 1、eval() 例: eval(string $code) 把字符串code作为PHP代码执行 2、assert() assert( mixed $assertion [, string $description ]) 检查一个断言是否为 FALSE,如果 assertion 是字符串,它将会被 assert()当做 PHP 代码来执行。 3、p…

秋招突击——算法打卡——6/3——复习{最低通行费、(状态压缩DP)小国王}——新做:{罗马数字转整数、最长公共前缀}

文章目录 复习背包模型——最低通行费题目内容实现代码 &#xff08;状态压缩DP&#xff09;小国王检查状态本身是否存在两个连续的1计算所有的合法状态已经所有合法状态之间的转移动态规划过程 新作罗马数字转整数个人实现实现代码 参考做法实现代码 最长公共前缀个人实现参考…

【车载开发系列】删除DTC操作步骤(VacanoVSB实现)

【车载开发系列】删除DTC操作步骤(VacanoVSB实现) 【车载开发系列】删除DTC操作步骤(VacanoVSB实现) 【车载开发系列】删除DTC操作步骤(VacanoVSB实现)Step1:Internal Behavior Editor对应Step2:CSWC删除1)删除InnerView関数12)删除InnerView関数23)删除InnerView関…

Docker无法stop或者rm指定容器

Docker无法stop或者rm指定容器 今日准备重启一下docker 容器部署的 Nginx 时&#xff0c;使用的命令是 docker exec -it ir-nginx nginx -s reload 结果发现无法重启报错 然后想着关闭再启动&#xff0c;结果发现 docker restart 、docker stop 、docker kill 、docker exec 都…

【科学文献计量】使用Endnote软件打开中国知网导出的文献期刊解析不正确问题解决

使用Endnote软件打开中国知网导出的文献期刊解析不正确问题解决 问题解决问题 新建一个Endnote的材料库,然后把下载好的中国知网文献数据(知网数据导出的是Endnote格式样式)导入进来。找到文件所在路径,导入的类型选择是“Endnote import”,然后点击确定,界面结果如下 …

汇编:数据定义数据填充

数组的定义 在32位汇编语言中&#xff0c;定义数组时&#xff0c;通常使用定义数据指令&#xff08;如 DB, DW, DD,DQ &#xff09;和标签来指定数组的名称和内容。DB定义字节数组&#xff08;每个元素占1字节&#xff09;、DW定义字数组&#xff08;每个元素占2字节&#xff…

CAD 文件(DXF / DWG)转换为(DXF / PDF / PNG / SVG)

方法一Github 这个是ezdxf出品的&#xff0c;可以使用命令行的方式进行转换 ezdxf draw -o file.<png|svg|pdf> <file.dxf>也可以自己改动代码 examples/addons/drawing/pdf_export.py 但是直接运行会有误&#xff0c;以下是我改动后的代码&#xff1a; from ez…

#13前端后花园周刊-10个现代 Node.js 运行时新特性、Nextjs15、Astro4.9、CSS压缩

⚡️行业动态 JavaScript 的创建者 Brendan Eich 在 Twitter/X 上出现&#xff0c;反驳了 JS 是“最邋遢的”的说法&#xff0c;称其只有 50% 。 &#x1f4c6;发布 Next.js 15 RC 流行的 React 元框架已经准备好迎接一个主要的新版本&#xff0c;它有一个 RC&#xff0c;让…

Excel中,如何将故意留空的单元格填充为上一级的值。

在Excel中&#xff0c;你可以使用以下方法将故意留空的单元格填充为上一级的值。 方法一&#xff1a;使用查找和替换功能 选择需要填充的区域。按 CtrlG 打开“定位”对话框&#xff0c;然后点击“定位条件”。选择“空值”&#xff0c;然后点击“确定”。这将选择所有空单元…

VS2015 +Qt 新建单元测试工程报错error LNK2019,error LNK2001: 无法解析的外部符号 WinMain

项目场景&#xff1a; 使用Qt5.9.9和vs2015进行单元测试工程的创建 问题描述 创建完成后&#xff0c;编译项目&#xff0c;报错&#xff1a; error LNK2019&#xff0c;error LNK2001: 无法解析的外部符号 WinMain 原因分析&#xff1a; 原因是笔者创建工程的时候&#xf…

python如何base64编码与解码操作???

前言 之前的文章有提到Base64编码的实现原理&#xff0c;你一定非常想尝试一下&#xff0c;对吧&#xff1f;对&#xff0c;你非常想尝试一下&#xff08;不接受反驳&#xff0c;你想你想你很想&#xff09;。既然你这么想尝试&#xff0c;那今天来看一下在python中如何使用Ba…