tinyxml2的入门教程

news2024/12/24 0:35:02

tinyxml2的入门教程

  • 前言
  • 一、tinyxml2 创建xml 文件
  • 二、tinyxml2 添加数据
  • 三、tinyxml2 更改数据
  • 四、tinyxml2 删除数据
  • 五、tinyxml2 打印
  • 总结


前言

xml 是一种标记型文档,有两种基本解析方式:DOM(Document Object Model,文档对象模型)和SAX(Simple APIs for XML,简单应用程序接口)。

在这里插入图片描述

DOM 将 xml 文档全部内容解析成一个对象模型树,通过对这个对象模型进行操作来实现对数据的操作。

  • 优点:
    – 解析成树的结构对象,可以实现增删改操作

  • 缺点:
    – 当 xml 文件过大时,比较占用内存

SAX 以事务为驱动,对 xml 文档从上之下,一行一行解析,当解析到事务对象则返回。

  • 优点:
    – 一行一行解析,内存占用小

  • 缺点:
    – 无能进行增删改操作

目前,有很多库封装了对 xml 文档的操作,例如 mini-xml 、libxml2、Xerces和 tinyxml等。tinyxml2 是其中一个比较简单且高效的 C ++ xml 解析器,只有一个.h 的头文件和一个 . pp 的源文件,可以轻松集成进自己的程序中。

tinyxml2采用DOM解析方式,

在 tinyxml2 中,节点是解析的基本单元,包括 文档节点(XMLDocument)、元素节点(XMLElement)、属性节点(XMLAttribute)和文本节点(XMLText)。对于 xml 文档中数据的增删改查都是基于这些节点进行操作的。

一、tinyxml2 创建xml 文件

首先,最好把 tinyxml2 的头文件和源文件放项目下:

在这里插入图片描述
然后就是引入 tinyxml2 的头文件并链接源文件。这里,用的是 cmake 来构建,将 tinyxml2 文件夹的路径包含进来,然后将源文件链接到 可执行文件上就行。

在这里插入图片描述
最后,假设现在创建一个关于 地图的 xml 数据文件

#include <iostream>
#include "tinyxml2/tinyxml2.h"

using namespace std;
using namespace tinyxml2;

struct point {
    double x;
    double y;
    point(double x, double y) : x(x), y(y) {};
};

// 创建一个XML文件
int createXML(const char *xmlPath) {
    // 定义文档节点
    XMLDocument xmlDoc;
    // 如果文件存在,则返回-1
    if (xmlDoc.LoadFile(xmlPath) != XML_ERROR_FILE_NOT_FOUND) {
        cout << "The xml file is exits" << endl;
        return -1;
    }

    // 创建根节点 <MAP>
    XMLElement *root = xmlDoc.NewElement("MAP");
    xmlDoc.InsertFirstChild(root);

    // 创建根节点下的 header 元素节点
    XMLElement *header = xmlDoc.NewElement("header");
    root->InsertFirstChild(header);

    // 设置 header 元素节点的属性
    header->SetAttribute("type", "");
    header->SetAttribute("name", "两驱MRL1300-无反识别");

    // 创建并设置 header 节点下的 min_pos 和 max_pos 元素节点
    XMLElement *min_pos = xmlDoc.NewElement("min_pos");
    min_pos->SetAttribute("x", "-46.00000");
    min_pos->SetAttribute("y", "-57.000000");
    header->InsertFirstChild(min_pos);

    XMLElement *max_pos = xmlDoc.NewElement("max_pos");
    max_pos->SetAttribute("x", "91.00000");
    max_pos->SetAttribute("y", "43.000000");
    header->InsertFirstChild(max_pos);

    // 在根节点下 加个注释
    root->InsertNewComment("This is a comment");

    // 在根节点下 加入 footer 元素节点,并设置文本内容
    XMLElement *footer = xmlDoc.NewElement("footer");
    footer->InsertNewText("This is a footer");
    root->InsertEndChild(footer);

    // 保存 xml 文件
    return xmlDoc.SaveFile(xmlPath);
}

int main(int argc, char *argv[]) {
    srand(unsigned(time(NULL)));
    const char *filename = "MAP.xml";
    if(createXML(filename) != XML_SUCCESS)
    {
        cout<<"Create xml file failed"<<endl;
        return 0;
    }
}

没指定决定路径的话,可以在编译文件夹中看到已经创建了一个 MAP.xml 文件

在这里插入图片描述

二、tinyxml2 添加数据

现在,为刚创建的 MAP.xml 文件,添加一些点云坐标

int addXML(const char *XMLPath) {
    // 文档节点 xmlDoc
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取文档节点的 根节点 root
    XMLElement *root = xmlDoc.RootElement();
    // 添加一些随机坐标点
    for (int i = 0; i < 100; i++) {
        point p(rand() * 0.001, rand() * 0.002);
        // 定义坐标元素节点 point
        XMLElement *point = xmlDoc.NewElement("point");
        // 设置元素节点 point 的属性和值
        point->SetAttribute("x", p.x);
        point->SetAttribute("y", p.y);

        // 将元素节点 point 添加到根节点 root下
        root->InsertEndChild(point);
    }
    // 保存 xml 文件
    return xmlDoc.SaveFile(XMLPath);
}

可以看到,已经在root节点中加入了 坐标元素了

在这里插入图片描述

三、tinyxml2 更改数据

更改操作里面就用到了 查询 操作(判断):将 x 属性值为0 的所有点元素的 y 属性值都改为2,在改之前,先添加一些x为0的点元素,在addXML()中加入:

// 添加一些指定点
    for (int i = 0; i < 100; i++) {
        point p(0,  1);
        // 定义坐标元素节点 point
        XMLElement *point = xmlDoc.NewElement("point");
        // 设置元素节点 point 的属性和值
        point->SetAttribute("x", p.x);
        point->SetAttribute("y", p.y);

        // 将元素节点 point 添加到根节点 root下
        root->InsertEndChild(point);
    }

在随机坐标点下就有了指定坐标点了

在这里插入图片描述

然后再进行查询并修改这些点

int modifyXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取 文档节点中的 root 根节点
    XMLElement *root = xmlDoc.RootElement();
    // 定义要修改的元素节点
    XMLElement *point = root->FirstChildElement("point");
    // 将所有 x 属性为 0 的 point 的 y 属性值都改为 2
    while (point != nullptr) {
        const char *x = point->Attribute("x");
        if (x && strcmp(x, "0") == 0) {
            point->SetAttribute("y", 2);
            cout << "modify done" << endl;
        }
        point = point->NextSiblingElement("point");
    }
    // 保存
    return xmlDoc.SaveFile(XMLPath);
}

这样,就将 x 属性值为 0 点的 y 属性值改为2了

在这里插入图片描述

四、tinyxml2 删除数据

这里,删除 x 属性值为 0 的 point 元素。

int deleteXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取 根节点 root
    XMLElement *root = xmlDoc.RootElement();

    // 准备要被删除的元素
    XMLElement *point = root->FirstChildElement("point");
    while (point != nullptr) {
        const char *x = point->Attribute("x");
        // 删除 x 属性值 为 0 的 point 元素
        if (x && strcmp(x, "0") != 0) {
            point = point->NextSiblingElement("point");
        } else {
            XMLElement *delete_point = point;
            point = point->NextSiblingElement("point");
            root->DeleteChild(delete_point);
            cout << "delete done" << endl;
        }
    }
    // 保存
    return xmlDoc.SaveFile(XMLPath);
}

这样, x 属性值为 0 的 point 元素就被全部删除了

在这里插入图片描述

五、tinyxml2 打印

void printXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return;
    }
    XMLPrinter printer;
    xmlDoc.Print(&printer);
    cout << printer.CStr() << endl;
}

在这里插入图片描述

总结

tinyxml2 解析 xml 文件的过程操作还是比较简单易上手的。最后,完整代码如下:

#include <iostream>
#include "tinyxml2/tinyxml2.h"

using namespace std;
using namespace tinyxml2;

struct point {
    double x;
    double y;
    point(double x, double y) : x(x), y(y) {};
};

// 创建一个XML文件
int createXML(const char *xmlPath) {
    // 定义文档节点
    XMLDocument xmlDoc;
    // 如果文件存在,则返回-1
    if (xmlDoc.LoadFile(xmlPath) != XML_ERROR_FILE_NOT_FOUND) {
        cout << "The xml file is exits" << endl;
        return -1;
    }

    // 创建根节点 <MAP>
    XMLElement *root = xmlDoc.NewElement("MAP");
    xmlDoc.InsertFirstChild(root);

    // 创建根节点下的 header 元素节点
    XMLElement *header = xmlDoc.NewElement("header");
    root->InsertFirstChild(header);

    // 设置 header 元素节点的属性
    header->SetAttribute("type", "");
    header->SetAttribute("name", "激光点云地图");

    // 创建并设置 header 节点下的 min_pos 和 max_pos 元素节点
    XMLElement *min_pos = xmlDoc.NewElement("min_pos");
    min_pos->SetAttribute("x", "-46.00000");
    min_pos->SetAttribute("y", "-57.000000");
    header->InsertFirstChild(min_pos);

    XMLElement *max_pos = xmlDoc.NewElement("max_pos");
    max_pos->SetAttribute("x", "91.00000");
    max_pos->SetAttribute("y", "43.000000");
    header->InsertFirstChild(max_pos);

    // 在根节点下 加个注释
    root->InsertNewComment("This is a comment");

    // 在根节点下 加入 footer 元素节点,并设置文本内容
    XMLElement *footer = xmlDoc.NewElement("footer");
    footer->InsertNewText("This is a footer");
    root->InsertEndChild(footer);

    // 保存 xml 文件
    return xmlDoc.SaveFile(xmlPath);
}

int addXML(const char *XMLPath) {
    // 文档节点 xmlDoc
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取文档节点的 根节点 root
    XMLElement *root = xmlDoc.RootElement();
    // 添加一些指定点
    for (int i = 0; i < 100; i++) {
        point p(0,  1);
        // 定义坐标元素节点 point
        XMLElement *point = xmlDoc.NewElement("point");
        // 设置元素节点 point 的属性和值
        point->SetAttribute("x", p.x);
        point->SetAttribute("y", p.y);

        // 将元素节点 point 添加到根节点 root下
        root->InsertEndChild(point);
    }
    // 添加一些随机坐标点
    for (int i = 0; i < 100; i++) {
        point p(rand() * 0.001, rand() * 0.002);
        // 定义坐标元素节点 point
        XMLElement *point = xmlDoc.NewElement("point");
        // 设置元素节点 point 的属性和值
        point->SetAttribute("x", p.x);
        point->SetAttribute("y", p.y);

        // 将元素节点 point 添加到根节点 root下
        root->InsertEndChild(point);
    }

    // 保存 xml 文件
    return xmlDoc.SaveFile(XMLPath);
}


int modifyXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取 文档节点中的 root 根节点
    XMLElement *root = xmlDoc.RootElement();
    // 定义要修改的元素节点
    XMLElement *point = root->FirstChildElement("point");
    // 将所有 x 属性为 0 的 point 的 y 属性值都改为 2
    while (point != nullptr) {
        const char *x = point->Attribute("x");
        if (x && strcmp(x, "0") == 0) {
            point->SetAttribute("y", 2);
            cout << "modify done" << endl;
        }
        point = point->NextSiblingElement("point");
    }
    // 保存
    return xmlDoc.SaveFile(XMLPath);
}

int deleteXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return -1;
    }
    // 获取 根节点 root
    XMLElement *root = xmlDoc.RootElement();

    // 准备要被删除的元素
    XMLElement *point = root->FirstChildElement("point");
    while (point != nullptr) {
        const char *x = point->Attribute("x");
        // 删除 x 属性值 为 0 的 point 元素
        if (x && strcmp(x, "0") != 0) {
            point = point->NextSiblingElement("point");
        } else {
            XMLElement *delete_point = point;
            point = point->NextSiblingElement("point");
            root->DeleteChild(delete_point);
            cout << "delete done" << endl;
        }
    }
    // 保存
    return xmlDoc.SaveFile(XMLPath);
}

void printXML(const char *XMLPath) {
    // 文档节点
    XMLDocument xmlDoc;
    if (xmlDoc.LoadFile(XMLPath) != XML_SUCCESS) {
        cout << "The xml file is not exits" << endl;
        return;
    }
    XMLPrinter printer;
    xmlDoc.Print(&printer);
    cout << printer.CStr() << endl;
}


int main(int argc, char *argv[]) {
    srand(unsigned(time(NULL)));
    const char *filename = "MAP.xml";
    if(createXML(filename) != XML_SUCCESS)
    {
        cout<<"Create xml file failed"<<endl;
        return 0;
    }
    if (addXML(filename) != XML_SUCCESS) {
        cout << "Add xml file failed" << endl;
        return 0;
    }
    if (modifyXML(filename) != XML_SUCCESS) {
        cout << "Modify xml file failed" << endl;
        return 0;
    }
    if (deleteXML(filename) != XML_SUCCESS) {
        cout << "Delete xml file failed" << endl;
        return 0;
    }
    printXML(filename);

}

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

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

相关文章

C++ 数字和数组解析

文章目录 1. 定义数字 2. 数学运算 3. 随机数 4. 数组 声明数组 初始化数组 5. 访问数组元素 6. 数组类型 7. 多维数组 二维数组 初始化二维数组 访问二维数组元素 8. 指向数组的指针 9. 传递数组给函数 10. 从函数返回数组 1. 定义数字 通常&#xff0c;当需要…

嵌入式人工智能(23-基于树莓派4B的温湿度传感器DHT11)

1、湿度传感器 目前市面上&#xff0c;仅测量湿度的传感器很少&#xff0c;普遍使用的都是温/湿度传感器&#xff0c;即以温/湿度一体式的探 头作为测温元件&#xff0c;将温度和湿度信号采集出来&#xff0c;再经过稳压滤波、运算放大、非线性校正、V转换、恒流及反向保护等电…

[Meachines] Lame smbd3.0-RCE

信息收集 IP AddressOpening Ports10.10.10.3TCP:21,22,139,445,3632 $ nmap -p- 10.10.10.3 --min-rate 1000 -sC -sV 21/tcp open ftp vsftpd 2.3.4 |_ftp-anon: Anonymous FTP login allowed (FTP code 230) | ftp-syst: | STAT: | FTP server status: | …

【Stable Diffusion】(基础篇五)—— 使用SD提升分辨率

使用SD提升分辨率 本系列博客笔记主要参考B站nenly同学的视频教程&#xff0c;传送门&#xff1a;B站第一套系统的AI绘画课&#xff01;零基础学会Stable Diffusion&#xff0c;这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 在前期作画的…

【NoSQL数据库】Redis知识小册

一、缓存穿透 缓存穿透是先查Redis&#xff0c;发现缓存中没有数据&#xff0c;再查数据库。然而&#xff0c;如果查询的数据在数据库中也不存在&#xff0c;那么每次查询都会绕过缓存&#xff0c;直接落到数据库上。 解决方案一、缓存空数据 查询Redis缓存&#xff1a;首先查…

独立开发者系列(34)——node项目部署

本节梳理node项目的部署&#xff0c;搭建一个外部能正常访问的node网站。将开发好的项目搭建到系统里面。Node的部署比PHP版本要复杂一些。部署项目前要理解几个概念。Nodejs版本管理器概念。 NVM概念&#xff0c;我们平时开发是在本地电脑上开发&#xff0c;开发的时候&#x…

计算机毕业设计:基于SSM的宠物领养系统

私信获取完整代码 一、选题背景介绍 &#x1f4d6;☕️&#x1f30a;&#x1f4dd;&#x1f4da;&#x1f3a9;&#x1f680;&#x1f4e3; &#x1f3a9; 宠物领养系统&#xff1a;帮助爱宠人士更好的去查看可以领养的宠物&#xff0c;帮助宣传相关保护宠物相关知识 &…

PHP家政系统自营+多商户独立端口系统源码小程序

家政行业的新篇章 引言&#xff1a;家政行业的数字化转型 近年来&#xff0c;随着科技的飞速发展和人们生活节奏的加快&#xff0c;家政服务行业也迎来了数字化转型的浪潮。为了提升服务效率、优化用户体验&#xff0c;越来越多的家政公司开始探索“家政系统自营多商户小程序…

Qt Designer的父子部件样式表设置学习

在Qt Designer中新建图像界面&#xff0c;放置两个QWidget&#xff0c;命名为widget_1和widget_2&#xff1b;两个QPushButton&#xff0c;pushButton_1和pushButton_2。 它们的父子从属关系如下&#xff1a; 设置widget_1的样式表&#xff1a; QWidget{ background-color: r…

lua 游戏架构 之 游戏 AI (八)ai_tbl 行为和优先级

定义一系列的AI行为类型和它们的优先级&#xff0c;以及一个映射表ai_tbl来关联每种AI行为类型与对应的脚本文件和优先级。以下是对代码的详细解释&#xff1a; lua 游戏架构 之 游戏 AI &#xff08;一&#xff09;ai_base-CSDN博客https://blog.csdn.net/heyuchang666/artic…

构建现代化农业产业服务平台的系统架构

随着全球农业产业的发展和技术的进步&#xff0c;农业生产管理面临着越来越复杂的挑战和机遇。建立一个现代化的农业产业服务平台系统架构&#xff0c;不仅能够提高农业生产效率和管理水平&#xff0c;还能促进农民收入增长和可持续发展。本文将探讨如何设计和实施这样一个系统…

git配置环境变量

一.找到git安装目录 打开此git安装目录下的bin文件&#xff0c;复制此文件路径 二.配置环境变量 2.1 右键点击此电脑的属性栏 2.2 点击高级系统配置 2.3 点击环境变量 2.4 按图中步骤进行配置 三.配置完成 win r 输入cmd打开终端 终端页面中输入 git --version 如图所示…

PySide(PyQt)的QPropertyAnimation(属性动画)

学不完&#xff0c;根本学不完:(&#xff0c;感觉逐渐陷入了学习深渊。。。 QPropertyAnimation 是 PySide(PyQt) 中一个用于在时间轴上平滑地改变对象属性的类。它常用于制作动画效果&#xff0c;比如移动、缩放或改变透明度等。 基本概念 QPropertyAnimation 是 Qt …

文件包含漏洞--pyload

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.PHP伪协议利用 php://协议 php://filter &#xff1a;用于在读取作用和写入文件时进行过滤和转换操作。 作用1&#xff1a;利用base64编码过滤器读取源码 通常利用文件包含执行php://filte…

17.5【C语言】static的补充说明

static &#xff08;静态的) 作用&#xff1a;修饰局部变量&#xff0c;修饰全局变量&#xff0c;修饰函数 对比两段代码 #include <stdio.h> void test() {int a 5;a;printf("%d ", a); } int main() {int i 0;for(i0; i<5; i){test();}return 0; } …

ElasticSearch(三)—文档字段参数设置以及元字段

一、 字段参数设置 analyzer&#xff1a; 指定分词器。elasticsearch 是一款支持全文检索的分布式存储系统&#xff0c;对于 text类型的字段&#xff0c;首先会使用分词器进行分词&#xff0c;然后将分词后的词根一个一个存储在倒排索引中&#xff0c;后续查询主要是针对词根…

【H.264】H.264详解(二)—— H264视频码流解析示例源码

文章目录 一、前言二、示例源码【1】目录结构【2】Makefile源码【3】h264parser.c源码【4】编译运行【5】源码下载地址 声明&#xff1a;此篇示例源码非原创&#xff0c;原作者雷霄骅。雷霄骅&#xff0c;中国传媒大学通信与信息系统专业博士生&#xff0c;在此向雷霄骅雷神致敬…

SEO与数据中心代理IP的结合能带来哪些便利?

本文将探讨将SEO与数据中心代理IP结合所带来的好处&#xff0c;以及如何利用这种组合来提升网站在搜索引擎中的排名和可见性。 1. 数据中心代理IP的作用和优势 数据中心代理IP指的是由数据中心提供的IP地址&#xff0c;用于隐藏真实服务器的位置和身份。与其他类型的代理IP相…

FFmpeg解复用器如何从封装格式中解析出不同的音视频数据

目录 1、ffmpeg介绍 2、FFMPEG的目录结构 3、FFmpeg的格式封装与分离 3.1、数据结构 3.2、封装和分离(muxer和demuxer) 3.2.1、Demuxer流程 3.2.2、Muxer流程 4、总结 4.1、播放器 4.2、转码器 C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…