使用c语言libexpat开源库解析XML数据
1 libexpat简介
- Expat 是一个用 C 语言编写的开源 XML 解析库,以其高性能和小巧的体积著称。Expat 兼容多种操作系统平台,包括但不限于 Windows、Linux、macOS 等。由于其跨平台特性和简单易用的API,Expat 成为了许多C/C++程序员解析XML文档的首选工具之一。
- 主要特性:
- 面向流的解析器:Expat 不像 DOM 解析器那样把整个XML文档加载到内存中形成树状结构,而是采用逐行解析的方式处理XML数据。这意味着它适合处理大型或者无限流式的XML数据输入,因为它不需要一次性加载整个文档到内存。
- 事件驱动解析:Expat 使用回调函数机制来报告解析过程中的事件,如元素开始、元素结束、字符数据块等。开发者需要提供这些回调函数,并通过 Expat API 注册,以便在解析过程中接收并处理这些事件。
- 轻量级和高效:Expat 因其简洁的设计和快速的解析速度而受到青睐,尤其对于资源受限的环境或者对性能要求较高的应用来说是一个理想的选择。
2 环境部署
- 如果自己不想编译源代码,可使用我已经编译好的 expat使用,直接跳过环境部署介绍。
- expat源码下载地址
2.1 Windows平台编译
- Winodws平台编译需要安装Visual Studio,推荐使用2015及以上版本。
- 下载源码后解压进入代码根目录下的expat目录中,创建一个build_x84文件夹,在build_x86文件夹中执行以下命令
-
cmake -G "Visual Studio 14 2015" ..cmake --build ./ --config Release
- 编译成功后,会在expat\build_x86\Release目录下生成对应的静态库和动态库
- 还需要用到3个头文件,expat\build_x86目录下会生成一个expat_config.h头文件,expat\lib目录下有expat.h和expat_external.h这两个头文件。
- 将对应的库文件和这三个头文件拷贝到我们的工程中。
2.2 Linux平台编译
- Linux平台推荐使用Centos7编译
- 同样解压后进入代码根目录下的expat目录中,创建一个build_x64文件夹,在build_x64文件夹中依次执行以下命令
-
./buildconf.sh # 执行后会生成configure文件./configure --prefix=${PWD}/_install sudo make #编译sudo make install # 安装,会安装到执行configure时--prefix参数指定目录下,不指定会安装到默认目录下
- 执行完以上命令在expat/_install目录下会生成头文件、库文件和可执行程序等。
- 将头文件和库文件拷贝到我们的工程目录下。
3 接口介绍
- 介绍下常用的几个API接口,有几个函数可能不好理解,在4章节的demo中会结合实例说明。
3.1 创建XML解析器实例
-
/** encoding: 规定输出编码,填NULL默认为UTF-8,支持ISO-8859-1, UTF-8, US-ASCII 这三种编码方式* 返回值: 创建成功返回一个XML解析器实例,创建失败返回NULL*/XML_Parser XML_ParserCreate(const XML_Char *encoding);
3.2 设置用户自定义的数据
-
/** parser: XML解析器实例* userData: 指向任意类型数据的指针。可以指向用户自定义的数据结构,通常是为了在解析过程中传递上下文信息或者存储解析结果*/void XML_SetUserData(XML_Parser parser, void *userData);
3.3 注册处理XML数据开始和结束事件的回调函数
-
/** parser: XML解析器实例* start: 处理元素开始事件的回调函数,可查看3.7* end: 处理元素结束事件的回调函数,可查看3.8*/void XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end);
3.4 注册处理XML文本内容事件的回调函数
-
/** parser: XML解析器实例* handler: 处理XML数据中的文本内容的回调函数,可查看3.9*/void XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler handler);
3.6 解析缓冲区中的XML数据
-
/** parser: XML解析器实例* buffer: XML数据的缓冲区* isFinal: 指示本次调用是否代表了整个XML输入的结束* 返回值: 成功返回 XML_STATUS_OK*/XML_Status XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) ;
3.7 处理XML数据字段开始的回调函数
-
/** 说明: 首先通过3.3接口注册这个回调函数,然后执行3.6接口开始解析,每碰到一个新字段这个函数就被回调一次* userData: 通过3.2接口传递进来的参数,可通过这个值将解析出来的数据返回出去* name: 开始字段名称* atts: 指向NULL结尾的XML_Char指针数组, 每两个连续的元素构成一个键值对,分别表示元素的属性名和属性值*/void(XMLCALL *XML_StartElementHandler)(void *userData, const XML_Char *name, const XML_Char **atts);
3.8 处理XML数据字段结束的回调函数
-
/** 说明: 首先通过3.3接口注册这个回调函数,然后执行3.6接口开始解析,每碰到一个字段结束这个函数就被回调一次* userData: 通过3.2接口传递进来的参数,可通过这个值将解析出来的数据返回出去* name: 开始字段名称*/void(XMLCALL *XML_EndElementHandler)(void *userData, const XML_Char *name);
3.9 处理XML数据文本内容的回调函数
-
/** 说明: 首先通过3.4接口注册这个回调函数,然后执行3.6接口开始解析,每碰到文本内容这个函数就被回调一次* userData: 通过3.2接口传递进来的参数,可通过这个值将解析出来的数据返回出去* s: 文本内容* len: 文本内容长度 */void(XMLCALL *XML_CharacterDataHandler)(void *userData, const XML_Char *s, int len);
4 实例演示
- XML测试数据
-
<?xml version="1.0"?><data><header hattr="http"><type>Post</type><host>127.0.0.1</host></header><body battr="base64"><data1>aGVsbG8=</data1><data2>ZXhwYXQ=</data2></body></data>
- 测试代码
-
#include <stdio.h>#include <expat.h>#include <iostream>#include <vector>#include <map>#ifndef _WIN32#include <string.h>#endif// 定义一个结构,保存字段名和字段值,这里为了演示简洁属性值就不保存了typedef struct USERDATA {std::string strName; //字段名std::string strValue; // 字段值}StUserData;// 调用 XML_Parse 开始解析数据后,只要碰到字段名,这个函数就会被调用// 比如碰到data开始时,该函数会被回调一次,碰到header开始时,会再次被回调void startElement(void *userData, const XML_Char *name, const XML_Char **atts){// 将字段名保存std::vector<StUserData> *vecData = (std::vector<StUserData>*)userData; StUserData stData;stData.strName.assign(name);vecData->insert(vecData->end(), stData);// 打印字段名printf("startElement name : %s\n", name);// 打印属性for (int i = 0; atts[i]; i += 2) {// 属性名和属性值printf("%s:%s\n", atts[i], atts[i + 1]);}}// 调用 XML_Parse 开始解析数据后,只要碰到字段名结束,这个回调函数就会被调用// 比如碰到header结束时,该函数会被回调一次void endElement(void *userData, const XML_Char *name){printf("endElement name : %s\n", name);}// 调用 XML_Parse 开始解析数据后,只要碰到文本,这个函数就会被回调// 比如碰到data和header时,并没有文本内容,下一层还有数据,因此不会被调用// 碰到type时,有文本内容了,是Post,因此该函数会被调用void characterData(void *userData, const XML_Char *s, int len) {// startElement 被调用后,只要对应的字段名有值,这个函数就会被调用// 所以文本值保存到最后一个数据中,保证字段名和文本内容对应std::vector<StUserData> *vecData = (std::vector<StUserData>*)userData;StUserData stData;stData.strName = vecData->at(vecData->size() - 1).strName;stData.strValue.assign(s, len);vecData->at(vecData->size() - 1) = stData;// 打印文本内容printf("value : ");for (int i = 0; i < len; i++) {printf("%c", s[i]);}printf("\n");}int main(int argc, const char *argv[]){std::vector<StUserData> vecData;XML_Parser parser = XML_ParserCreate(NULL);if (parser == NULL) {return -1;}// 设置用户自定义的数据XML_SetUserData(parser, &vecData);// 注册两个回调函数,分别处理元素的开始和结束事件XML_SetElementHandler(parser, startElement, endElement);// 注册一个回调函数来处理 XML 文档中元素内的文本内容XML_SetCharacterDataHandler(parser, characterData);// 开始解析数据const char* xmlData = "<?xml version=\"1.0\"?><data><header hattr=\"http\"><type>Post</type><host>127.0.0.1</host></header><body battr=\"base64\"><data1>aGVsbG8=</data1><data2>ZXhwYXQ=</data2></body></data>";if(!XML_Parse(parser, xmlData, strlen(xmlData), false)){printf("XML_Parse failed : %s at line %lu\n", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));system("pause");return -1;}printf("==================================================\n");// 打印我们在自己定义的数据结构中保存的数据for (int i = 0; i < vecData.size(); i++) {// 没有文本内容时只打印字段值if (vecData.at(i).strValue.empty()) {std::cout << vecData.at(i).strName.c_str() << std::endl;}else {std::cout <<" "<< vecData.at(i).strName.c_str() << " : " << vecData.at(i).strValue.c_str() << std::endl;}}// 释放xml解析器XML_ParserFree(parser);system("pause");return 0;}
- 输出结果
相关文章:
使用c语言libexpat开源库解析XML数据
1 libexpat简介 Expat 是一个用 C 语言编写的开源 XML 解析库,以其高性能和小巧的体积著称。Expat 兼容多种操作系统平台,包括但不限于 Windows、Linux、macOS 等。由于其跨平台特性和简单易用的API,Expat 成为了许多C/C程序员解析XML文档的…...
51单片机入门_江协科技_19~20_OB记录的笔记
19. 串口通讯 19.1. 串口介绍: •串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。 •单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的…...
基于k8s的高性能综合web服务器搭建
目录 基于k8s的高性能综合web服务器搭建 项目描述: 项目规划图: 项目环境: k8s, docker centos7.9 nginx prometheus grafana flask ansible Jenkins等 1.规划设计整个集群的架构,k8s单master的集群环境&…...
Folder Icons for Mac v1.8 激活版文件夹个性化图标修改软件
Folder Icons for Mac是一款Mac OS平台上的文件夹图标修改软件,同时也是一款非常有意思的系统美化软件。这款软件的主要功能是可以将Mac的默认文件夹图标更改为非常漂亮有趣的个性化图标。 软件下载:Folder Icons for Mac v1.8 激活版 以下是这款软件的一…...
Gitee上传私有仓库
个人记录 Gitee创建账号 以KS进销存系统为例,下载到本地电脑解压。 新建私有仓库 仓库名称:ks-vue3,选择‘私有’ 本地配置 下载安装git配置git 第一次配置可以在本地目录右键【Open Git Bash here】输入【Git 全局设置】再输入【创…...
HTMLCSSJS
HTML基本结构 <html><head><title>标题</title></head><body>页面内容</body> </html> html是一棵DOM树, html是根标签, head和body是兄弟标签, body包括内容相关, head包含对内容的编写相关, title 与标题有关.类似html这种…...
第14章 数据结构与集合源码
一 数据结构剖析 我们举一个形象的例子来理解数据结构的作用: 战场:程序运行所需的软件、硬件环境 战术和策略:数据结构 敌人:项目或模块的功能需求 指挥官:编写程序的程序员 士兵和装备:一行一行的代码 …...
分享react+three.js展示温湿度采集终端
前言 气象站将采集到的相关气象数据通过GPRS/3G/4G无线网络发送到气象站监测中心,摆脱了地理空间的限制。 前端:气象站主机将采集好的气象数据存储到本地,通过RS485等线路与GPRS/3G/4G无线设备相连。 通信:GPRS/3G/4G无线设备通…...
易宝OA ExecuteSqlForDataSet SQL注入漏洞复现
0x01 产品简介 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台,具有信息管理、 流程管理 、知识管理(档案和业务管理)、协同办公等多种功能。 0x02 漏洞概述 易宝OA ExecuteSqlForDataSet接口处存在SQL注入漏洞,未经身份认证的攻击者可以通过…...
C++语言学习(二)——⭐缺省参数、函数重载、引用
1.⭐缺省参数 (1)缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。 void Func(int a 0) {cout<<a<<endl; } int…...
qt通过setProperty设置样式表笔记
在一个pushbutton里面嵌套两个label即可,左侧放置图片label,右侧放置文字label,就如上图所示; 但是这时的hover,press的伪状态是没有办法“传递”给里面的控件的,对btn的伪状态样式表的设置,是不…...
Sora文本生成视频(附免费的专属提示词)
sora-时髦女郎 bike_1 Sara-潮汐波浪 Sora是一个由OpenAI出品的文本生成视频工具,已官方发布了生成视频的样式,视频的提示词是:A时髦的女人走在充满温暖霓虹灯的东京街道上动画城市标牌。她穿着黑色皮夹克、红色长裙和黑色靴子,拎着黑色钱包。她穿着太阳镜和红色唇膏。她走…...
Flask Python:数据库多条件查询,flask中模型关联
前言 在上一篇Flask Python:模糊查询filter和filter_by,数据库多条件查询中,已经分享了几种常用的数据库操作,这次就来看看模型的关联关系是怎么定义的,先说基础的关联哈。在分享之前,先分享官方文档,点击查看 从文档…...
Spring Security 实现后台切换用户
Spring Security version 后端代码: /*** author Jerry* date 2024-03-28 17:47* spring security 切换账号*/RestController RequiredArgsConstructor RequestMapping("api/admin") public class AccountSwitchController {private final UserDetailsSe…...
《QT实用小工具·一》电池电量组件
1、概述 项目源码放在文章末尾 本项目实现了一个电池电量控件,包含如下功能: 可设置电池电量,动态切换电池电量变化。可设置电池电量警戒值。可设置电池电量正常颜色和报警颜色。可设置边框渐变颜色。可设置电量变化时每次移动的步长。可设置…...
基于springboot实现墙绘产品展示交易平台管理系统项目【项目源码+论文说明】计算机毕业设计
基于springboot实现墙绘产品展示交易平台管理系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本墙绘产品展示交易平台就是在这样的大环境下诞生&…...
主流公链文章整理
主流公链文章整理 分类文章地址🍉BTC什么是比特币🥭BTCBTC网络是如何运行的🍑BTC一文搞懂BTC私钥,公钥,地址🥕ETH什么是以太坊🌶️基础知识BTC网络 vs ETH网络🥜CosmosCosmos介绍&a…...
css3之3D转换transform
css3之3D转换 一.特点二.坐标系三.3D移动(translate3d)1.概念2.透视(perpective)(近大远小)(写在父盒子上) 四.3D旋转(rotate3d)1.概念2.左手准则3.呈现(transfrom-style)(写父级盒子…...
SpringBoot -- 外部化配置
我们如果要对普通程序的jar包更改配置,那么我们需要对jar包解压,并在其中的配置文件中更改配置参数,然后再打包并重新运行。可以看到过程比较繁琐,SpringBoot也注意到了这个问题,其可以通过外部配置文件更新配置。 我…...
优酷动漫顶梁柱!神话大乱炖的修仙番为何火爆?
优酷动漫新晋顶梁柱,实时超160万在追的修仙番长啥样? 由优酷动漫联合玄机科技打造的《师兄啊师兄》俨然成为了国漫界一颗璀璨的新星。自去年开播以来热度口碑双丰收,今年在播的第二季人气更是节节攀升,稳坐优酷动漫榜第一把交椅。…...
每日一题:C语言经典例题之判断实数相等
题目: 从键盘输入两个正实数,位数不超过200,试判断这两个实数是否完全相等。注意输入的实数整数部分可能有前导0,小数部分可能有末尾0。 输入 输入两个正实数a和b。 输出 如果两个实数相等,则输出Yes,…...
【算法每日一练]-数论(保姆级教程 篇1 埃氏筛,欧拉筛)
目录 保证给你讲透讲懂 第一种:埃氏筛法 第二种:欧拉筛法 题目:质数率 题目:不喜欢的数 思路: 问题:1~n 中筛选出所有素数(质数) 有两种经典的时间复杂度较低的筛法࿰…...
【剑指offr--C/C++】JZ59 滑动窗口的最大值
一、题目 二、思路及代码 暴力解法是依次往后滑动一位,然后比较窗口内的值。 我这里考虑:窗口每次往后移动一位,那么如果当前窗口的最大值max在窗口内部,那么再滑动到下一个窗口的时候,窗口内只有最新进来的一个元素没…...
RabbitMQ Tutorial
参考API : Overview (RabbitMQ Java Client 5.20.0 API) 参考文档: RabbitMQ: One broker to queue them all | RabbitMQ 目录 结构 Hello World consumer producer 创建连接API解析 创建连接工厂 生产者生产消息 消费者消费消息 队列声明 工作队列Work Queues 公平…...
如何对Webpack进行优化
目录 1.优化-提取css代码 1.1. 插件 mini-css-extract-plugin 1.2. 步骤: 1.3. 注意 1.4. 好处 1.5. 练习 2. 优化-css代码提取后压缩 2.1. 问题引入 2.2. 解决 2.3. 步骤 3. Webpack打包less代码 3.1. 加载器 less-loader 3.2. 步骤 3.3. 注意…...
nut-ui中的menu 菜单组件的二次封装
这个菜单组件 一般可以直接用到项目里 如果复用性不强的话 直接使用 但是有一个问题 如果很多地方都需要用到这个组件 我们可以把这个组件二次封装一下 <template><div class"cinema-search-filter-component"><nut-menu><template #icon>&…...
python笔记(11)序列
Python中的“序列”是一个广义术语,用于描述一种特定的数据结构,它具备以下共同特征: 有序性:序列中的元素按照特定的顺序排列,每个元素在序列中都有一个确定的位置,即索引。 索引访问:通过索引…...
Rust egui(4) 增加自己的tab页面
如下图,增加一个Sins也面,里面添加一个配置组为Sin Paraemters,里面包含一个nums的参数,范围是1-1024,根据nums的数量,在Panel中画sin函数的line。 demo见:https://crazyskady.github.io/index.…...
小组分享第二部分:Jsoup
1.Jsoup是什么: 是HTML的解析器,可以解析URL地址,HTML的文本内容,可以使用DOM,CSS以及类似Jquery的操作方法来操作数据 2.Jsoup的作用 1.通过URL或者文件或者字符串获取到HTML页面并解析 2.使用DOM或CSS等操作来对数据进行操作 3.可以操作HT…...
C#(winform) 调用MATLAB函数
测试环境 VisualStudio2022 / .NET Framework 4.7.2 Matlab2021b 参考:C# Matlab 相互调用 Matlab 1、编写Matlab函数 可以没有任何参数单纯定义matlab处理的函数,输出的数据都存在TXT中用以后期读取数据 function [result,m,n] TEST(list) % 计算…...
写字楼装修公司/谷歌aso优化
安装 --网络 --存储 --用户 --对象 --ASM (包含前面的内容的复习)--内存管理 -- 备份 --闪回 -- 事务 --sql 编程 转载于:https://www.cnblogs.com/niaocaizhou/p/10848652.html...
中国英文政务网站建设/免费影视软件靠什么赚钱
文章来源: 点击打开 高斯滤波是一种线性平滑滤波,对于除去高斯噪声有很好的效果。在其官方文档中形容高斯滤波为”Probably the most useful filter”,同时也指出高斯滤波并不是效率最高的滤波算法。高斯算法在官方文档给出的解释是高斯滤波是通过对输入…...
建立网站要准备多少钱/北京seo百度推广
Eureka 服务器架起来了(关于架设步骤参考博客《Linux 下 Eureka 服务器的部署》),现在如何把我们要负载均衡的服务器(也就是从 Application Client 接收请求并返回一个响应的 Application Service)注册到 Eureka?本文以一个示例介绍 Eureka Application …...
做恋爱方面的网站/seo搜索优化待遇
中国矿业大学教职工代表大会第一次会议暨工会会员中国矿业大学第八届教职工代表大会暨第十四届工会会员代表大会第一次会议代表团代表名单(以姓氏笔画为序)(共18个代表团593名代表,其中:正式代表368人、特邀代表 30人、列席代表 195 人)矿业工程学院、安…...
wordpress初始化/域名解析ip
1.环境说明 主机名IP地址备注redis1192.168.157.165redis主服务器redis2192.168.157.166redis从服务器redis3192.168.157.167redis从服务器 注意:操作系统 关闭防火墙、SELinux、并在hosts中添加主机名和IP地址的对应关系 3.上传介质 上传redis安装介质redis-3.0.…...
企业网站建设 南通/南宁推广软件
按Ctrl0即可。UltraEdit有10个剪切板(clipboard),分别用Ctrl0 - Ctrl9 切换. Ctrl0 是 Windows 的,其他则为用户自定义的<script>window._bd_share_config{"common":{"bdSnsKey":{},"bdText":"","…...