C++ XML文件和解析

XML(可扩展标记语言)是一种用于存储和传输数据的标记语言。它具有自描述性和平台无关性的特点。XML 文档的格式主要由一组嵌套的元素和属性构成,结构清晰,易于理解和解析。

XML 文档的基本格式

一个 XML 文档通常包括以下部分:

  • XML 声明:标识文档和版本信息。
  • 根元素:整个 XML 文档只能有一个根元素,所有其他元素必须嵌套在根元素内。
  • 元素:具有开始标签和结束标签,可以嵌套其他元素。
  • 属性:为元素提供额外的信息。
  • 文本内容:元素可以包含文本内容。
  • 注释:用于注释文档内容。

具体示例

以下是一个简单的 XML 文档示例,展示了上述基本部分:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 这是一个示例 XML 文档 -->
<bookstore><book category="cooking"><title lang="en">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book><book category="children"><title lang="en">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book><book category="web"><title lang="en">Learning XML</title><author>Erik T. Ray</author><year>2003</year><price>39.95</price></book>
</bookstore>

XML 文档的详细部分

XML 声明

<?xml version="1.0" encoding="UTF-8"?>

这是文档的声明部分,指定了 XML 版本和编码方式。

注释

<!-- 这是一个示例 XML 文档 -->

注释可以放在 XML 文档中的任何位置,不会被解析器处理。

根元素

<bookstore><!-- 所有内容都必须在根元素内部 -->
</bookstore>

bookstore 是根元素,所有其他元素都嵌套在其中。

元素

<book category="cooking"><title lang="en">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price>
</book>

book 是一个元素,其中包含了多个子元素和一个属性 category。

属性

<book category="cooking"><title lang="en">Everyday Italian</title><!-- 其他子元素 -->
</book>

category 和 lang 是属性,为元素提供额外的信息。

文本内容

<title lang="en">Everyday Italian</title>

title 元素包含了文本内容 Everyday Italian。

常见的 XML 结构

嵌套元素

<family><parent name="John"><child name="Doe" age="10"/><child name="Jane" age="8"/></parent>
</family>

元素可以嵌套其他元素,形成层级结构。

属性和子元素结合

<employee id="1001"><name>John Doe</name><department>HR</department><salary>5000</salary>
</employee>

元素可以同时包含属性和子元素。

自闭合元素

<img src="image.jpg" alt="Sample Image"/>

自闭合元素是一种简洁的表示方式,不包含子元素。

XML 文档的规则

  • 良好格式:XML 文档必须是良好格式的,即每个元素都必须正确关闭,元素必须正确嵌套,属性值必须用引号括起来。
  • 区分大小写:XML 标签是区分大小写的。
  • 根元素:每个 XML 文档必须有且只有一个根元素。
  • 特殊字符:某些字符(如 <, >, & 等)在 XML 中有特殊含义,需要使用转义序列(如 &lt;, &gt;, &amp;)表示。

XML文档解析

XML 文件解析通常有两种主要方式:DOM(Document Object Model)解析和 SAX(Simple API for XML)解析。这两种方法各有优缺点,适用于不同的应用场景。

DOM 解析

DOM 解析将整个 XML 文档读入内存中,并将其表示为一个树结构。每个节点在树中对应 XML 文档中的一个元素。用户可以通过 DOM API 访问和操作树中的节点。

优点
  • 易于使用:通过树结构可以方便地访问和操作 XML 文档中的任意节点。
  • 丰富的功能:支持随机访问和复杂的查询操作。
  • 标准化:DOM 是 W3C 标准,广泛支持和文档丰富。
缺点
  • 内存消耗大:需要将整个 XML 文档加载到内存中,对于大文件可能会导致高内存占用。
  • 性能较低:解析和构建整个文档树的开销较大,处理大文件时性能可能会成为瓶颈。
适用场景
  • 适用于需要频繁访问和操作 XML 文档的应用场景。
  • 适用于中小规模的 XML 文档。
示例(使用 TinyXML)
#include <tinyxml2.h>
using namespace tinyxml2;int main() {XMLDocument doc;doc.LoadFile("example.xml");XMLElement* root = doc.RootElement();if (root != nullptr) {XMLElement* element = root->FirstChildElement("ElementName");if (element != nullptr) {const char* text = element->GetText();printf("Element text: %s\n", text);}}return 0;
}

SAX 解析

SAX 解析是一种事件驱动的解析方法,逐行读取 XML 文档,并在遇到不同的结构(如开始标签、结束标签、文本节点等)时触发相应的事件处理函数。SAX 解析不会将整个文档加载到内存中,而是按需处理文档内容。

优点
  • 内存消耗低:不需要将整个文档加载到内存中,适合处理大文件。
  • 性能高:按顺序处理文档内容,解析速度快。
缺点
  • 使用复杂:事件驱动的编程模型较为复杂,需要编写事件处理函数。
  • 不支持随机访问:只能按顺序读取文档内容,无法直接访问任意节点。
适用场景
  • 适用于处理大型 XML 文档或内存有限的环境。
  • 适用于一次性读取和处理文档内容的场景。
示例(使用 Expat)
#include <expat.h>
#include <cstdio>
#include <cstdlib>void startElement(void *userData, const char *name, const char **atts) {printf("Start element: %s\n", name);
}void endElement(void *userData, const char *name) {printf("End element: %s\n", name);
}void characterData(void *userData, const char *s, int len) {printf("Character data: %.*s\n", len, s);
}int main() {FILE *file = fopen("example.xml", "r");if (!file) return 1;XML_Parser parser = XML_ParserCreate(NULL);XML_SetElementHandler(parser, startElement, endElement);XML_SetCharacterDataHandler(parser, characterData);char buffer[1024];size_t len;while ((len = fread(buffer, 1, sizeof(buffer), file)) != 0) {if (XML_Parse(parser, buffer, len, feof(file)) == XML_STATUS_ERROR) {fprintf(stderr, "Parse error at line %lu:\n%s\n",XML_GetCurrentLineNumber(parser),XML_ErrorString(XML_GetErrorCode(parser)));return 1;}}XML_ParserFree(parser);fclose(file);return 0;
}

总结

  • DOM 解析:适合需要随机访问和操作 XML 内容的场景,使用简单但内存和性能消耗较大。
  • SAX 解析:适合处理大文件或内存有限的场景,性能高但使用复杂。

tinyxml2 库

tinyxml2 是一款简单、小巧、高效的开源C++ xml解析库,在 tinyxml2 库中,XMLNode 是一个基类,它有几个派生类型。这些派生类型用于表示不同类型的 XML 节点。以下是 XMLNode 的主要派生类型:

XMLDocument:

  • 表示整个 XML 文档。
  • XMLDocument 是 XMLNode 的根,可以包含其他节点。
  • 提供了加载、保存和解析 XML 文档的功能。

XMLElement:

  • 表示 XML 文档中的一个元素(节点)。
  • 可以包含其他元素、属性和文本。
  • 是最常用的节点类型,用于表示 XML 标签。

XMLText:

  • 表示 XML 元素中的文本内容。
  • 用于包含实际的文本数据。

XMLComment:

  • 表示 XML 文档中的注释节点。
  • 注释节点内容不参与 XML 文档的逻辑处理,只用于提供额外的信息。

XMLDeclaration:

  • 表示 XML 文档的声明部分(如 <?xml version="1.0" encoding="UTF-8"?>)。
  • 通常在文档的最开始。

XMLUnknown:

  • 表示未知的 XML 节点类型。
  • 用于处理不符合其他已知节点类型的节点。

XMLAttribute:

  • 严格来说,XMLAttribute 不是从 XMLNode 派生的,但它用于描述 XML 元素的属性。
  • 属性节点包含名称和值,不直接参与 XML 文档的树结构。

tinyxml2解析有限元求解文件

一些有限元求解器的求解文件就是xml格式的,以开源FEM软件FEBio的求解文件为例,我们使用tinyxml2来提取里面的一些关键信息。

对于一个包含2万节点,12万单元的模型文件,我们通过tinyxml2解节点和单元信息花了0.3s,这个效率还是不错的。

如下为tinyxml2解析FEBio求解文件源码:

#include "tinyxml2.h"#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <sstream>
#include <chrono>using namespace std;
using namespace tinyxml2;class FemXmlParser
{
public:FemXmlParser(const char* xmlFile):xml_file(xmlFile) {}void parse() {XMLDocument doc;if (doc.LoadFile(xml_file) != XML_SUCCESS) {std::cerr << "Failed to load file: " << xml_file << std::endl;return;}XMLElement* febio = doc.FirstChildElement("febio_spec");if (!febio) {std::cerr << "No <febio_spec> element in XML file." << std::endl;return;}XMLElement* module = febio->FirstChildElement("Module");if (module) {const char* type = module->Attribute("type");std::cout << "Module Type: " << (type ? type : "Unknown") << std::endl;}XMLElement* geometry = febio->FirstChildElement("Mesh");if (geometry) {XMLElement* nodesElement = geometry->FirstChildElement("Nodes");if (nodesElement) ParseNodes(nodesElement);XMLElement* elementsElement = geometry->FirstChildElement("Elements");if (elementsElement) ParseElements(elementsElement);}XMLElement* materialsElement = febio->FirstChildElement("Material");if (materialsElement) ParseMaterials(materialsElement);XMLElement* controlElement = febio->FirstChildElement("Control");if (controlElement) ParseControl(controlElement);}void printSumaryInfo(){std::cout << "Nodes: total " <<nodes.size()<< std::endl;std::cout << "Elements: total " << elements.size()<< std::endl;std::cout << "Materials:" << std::endl;for (const Material& material : materials) {std::cout << "ID: " << material.id << ", Type: " << material.type << std::endl;}std::cout << "Control:" << std::endl;std::cout << "Analysis Type: " << control.analysis << std::endl;}void printDetailInfo(){// 测试输出,确保数据正确存储在容器中std::cout << "Nodes:" << std::endl;for (const Node& node : nodes) {std::cout << "ID: " << node.id << ", Position: (" << node.x << ", " << node.y << ", " << node.z << ")" << std::endl;}std::cout << "Elements:" << std::endl;for (const Element& element : elements) {std::cout << "ID: " << element.id << ", Node IDs: ";for (int nodeId : element.nodeIds) {std::cout << nodeId << " ";}std::cout << std::endl;}std::cout << "Materials:" << std::endl;for (const Material& material : materials) {std::cout << "ID: " << material.id << ", Type: " << material.type << std::endl;}std::cout << "Control:" << std::endl;std::cout << "Analysis Type: " << control.analysis << std::endl;}private:struct Node {int id;double x, y, z;};struct Element {int id;std::vector<int> nodeIds;};struct Material {int id;std::string type;};struct Control {std::string analysis;};vector<int> splitStringToInts(const string& str, char delimiter) {vector<int> result;size_t start = 0;size_t end = str.find(delimiter);while (end != string::npos) {result.push_back(stoi(str.substr(start, end - start)));start = end + 1;end = str.find(delimiter, start);}result.push_back(stoi(str.substr(start, end - start)));return result;}vector<double> splitStringToDoubles(const string& str, char delimiter) {vector<double> result;stringstream ss(str);string item;while (getline(ss, item, delimiter)) {result.push_back(stod(item));}return result;}void ParseNodes(XMLElement* nodesElement) {for (XMLElement* node = nodesElement->FirstChildElement("node"); node != nullptr; node = node->NextSiblingElement("node")) {Node n;node->QueryIntAttribute("id", &n.id);const char* nodeText = node->GetText();if (nodeText) {vector<double> ns = splitStringToDoubles(nodeText, ',');n.x = ns[0];n.y = ns[1];n.z = ns[2];}nodes.push_back(n);}}void ParseElements(XMLElement* elementsElement) {for (XMLElement* element = elementsElement->FirstChildElement("elem"); element != nullptr; element = element->NextSiblingElement("elem")) {Element e;element->QueryIntAttribute("id", &e.id);const char* elemText = element->GetText();if (elemText) {e.nodeIds = splitStringToInts(elemText, ',');}elements.push_back(e);}}void ParseMaterials(XMLElement* materialsElement) {for (XMLElement* material = materialsElement->FirstChildElement("material"); material != nullptr; material = material->NextSiblingElement("material")) {Material m;material->QueryIntAttribute("id", &m.id);m.type = material->Attribute("type");materials.push_back(m);}}void ParseControl(XMLElement* controlElement) {XMLElement* ctrl = controlElement->FirstChildElement("analysis");control.analysis = ctrl->GetText();}private:const char* xml_file;std::vector<Node> nodes;std::vector<Element> elements;std::vector<Material> materials;Control control;
};class Timer {
public:Timer() : start_time_point(std::chrono::high_resolution_clock::now()) {}void reset() {start_time_point = std::chrono::high_resolution_clock::now();}double elapsed() const {return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start_time_point).count() / 1000.0;  // 返回毫秒}void report(){double elapsed_time = elapsed();std::cout << "Elapsed time: " << elapsed_time << " ms" << std::endl;}
private:std::chrono::high_resolution_clock::time_point start_time_point;
};int main()
{Timer time;FemXmlParser parser("../big_file.xml");parser.parse();time.report();parser.printSumaryInfo();return 1;
}

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

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

相关文章

大模型狂奔不息的300天

大模型行业正如火如荼地发展着&#xff0c;那么&#xff0c;如何解读当前国内大模型行业的发展&#xff1f;谁又可能是大模型时代的超级应用&#xff1f;或许后一个问题的答案&#xff0c;现在还未能揭晓。一起来看看本文关于大模型行业发展的解读和分析。 2023年&#xff0c;没…

Linux线程 -- 互斥锁 和 条件变量

在多线程编程中&#xff0c;互斥量&#xff08;mutex&#xff09;是用于保护共享资源的同步机制&#xff0c;确保在任一时刻只有一个线程能够访问共享资源。互斥量用于防止竞态条件&#xff08;race conditions&#xff09;&#xff0c;确保数据一致性。 基本概念 互斥量&…

python学习笔记-04

高级数据类型 一组按照顺序排列的值称为序列&#xff0c;python中存在三种内置的序列类型&#xff1a;字符串、列表和元组。序列可以支持索引和切片的操作&#xff0c;第一个索引值为0表示从左向右找&#xff0c;第一个索引值为负数表示从右找。 1.字符串操作 1.1 切片 切片…

Unity 编辑器扩展 一键替换指定物体下的所有材质球

先看效果 实现方案 1&#xff1a;创建几个用于测试的Cube 2&#xff1a;创建一个脚本 3:编写脚本内容 主要是这部分的逻辑 附上完整代码 using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine;public class Tool {[MenuItem(…

json文件操作和异常处理

目录 按行读取文件readline() 读取大文件: json文件: json文件介绍: json的语法&#xff1a; 读取json文件: json文件写入: 异常&#xff1a; 捕获异常: 捕获指定类型的异常: 捕获未知类型的异常(使用最多): 异常捕获的完整结构: 异常传递: ​编辑抛出异常: 按行…

A6500-LC LVDT 前置器,用于A6500-UM, 导轨安装

电源 22.5V to 32VDC <30mA <0.1%/V <60V( 使用SELV/PELV 供电电源) 约2.2Vrms,5kHz IP20 IEC 60529 -35C to 75C(-31F to 167F) -35C to 85C(-31F to 185F) 电流损耗 供电电压对 运行温度 存储温度 0.35mm(0.014 in ),10 to 55Hz 15g 根据 EN 60068-2-27 根据IEC 613…

linux必学基础命令大全

一切皆文件&#xff0c;每个文件都有具体的用途 命令快捷查看目录 常用命令 - 目录类1、ls 查看当前目录下的文件2、man查看命令详细信息3、pwd 查看当前目录 -4、cd 进入目录5、清屏命令6、mkdir创建目录7、du查看文件或者文件夹大小 常用命令 - 文件类1、vim/vi使用2、cat 查…

Maven实战: 从工程创建自定义archetype

在上一节中(创建自定义archetype)我们手动创建了一个项目模板&#xff0c;经过5步能创建出一个项目模板&#xff0c;如果我有一个现成的项目&#xff0c;想用这个项目作为模板来生成其他项目呢&#xff1f;Maven提供了基于项目生成archetype模板的能力&#xff0c;我们分3步来讲…

Windows下 CLion中,配置 OpenCV、LibTorch

首先按照win下C部署深度学习模型之clion配置pytorchopencv教程记录 步骤配置。 LibTorch 部分 在测试LibTorch时会出现类似 c10.dll not found 的问题&#xff08;Debug才有&#xff09;&#xff1a; 参考C部署Pytorch&#xff08;Libtorch&#xff09;出现问题、错误汇总和 …

行业分析---造车新势力之理想汽车

1 前言 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 此类文章的受…

vulntarget-b记录(Sliver学习)

网络环境 域控&#xff08;Win2016&#xff09; vulntarget\administrator&#xff1a;Admin123、&#xff08;首次登陆要改密码修改为Admin123&#xff09; vulntarget\win101&#xff1a;admin#123 边界Web主机突破 nmap扫描发现81端口 通过扫描&#xff0c;fuzz出来了后…

DJI FlyCart 30 天空 “吊车”概念板评测!

从消费级无人机&#xff0c;到专业级无人机&#xff0c;再到行业级无人机&#xff0c;大疆的探索脚步从未停下。现在&#xff0c;大疆已经正式进入民用运载无人机行列&#xff01;就在8月16日&#xff0c;大疆正式发布首款民用运载无人机 —— DJI FlyCart 30。 作为大疆第一代…

Flutter基础 -- Flutter基础特性

目录 1. 一切都是 widget 1.1 UI 组件&#xff01;&#xff01;&#xff01; 1.2 架构设计 1.3 sdk 源码目录 1.4 widget 分类&#xff01;&#xff01;&#xff01; 参考文献 2. devTools 调试工具 2.1 启动调试器 2.2 布局面板 参考文献 3. 布局约束规则 3.1 让子…

亲,你有多久没有清理过你电脑的 DNS 缓存了?

最近明月因为工作关系更换了几次使用的电脑,期间就发现明明另一台电脑访问某个网址是正常,换一台电脑后就会出现无法访问的现象,并且用的还是同一个宽带网络,实在是太诡异了!后来还是突然想起来 DNS 缓存这个问题,立马清除了那台电脑的 DNS 缓存后,打不开的网址顺利的呈…

FPGA PCIe PIO代码的学习

目录 背景 应用场景 代码架构分析 结论 背景 本项目是基于xinlinx官方的PCIe IP 7 series integrated block for PCI Express。根据官方的例程加上官方给的example&#xff0c;对代码进行分析。 应用场景 对一些速率要求不高的&#xff0c;比如IO操作&#xff0c;推荐使用…

对新手友好的最简单方便的本地项目关联git远程仓库教程

对新手友好的最简单方便的本地项目关联git远程仓库教程 前置条件1.本地项目2.gitee上创建同名项目 关联操作1.在本地进行clone远程仓库操作2.把本地项目下的目录和文件都复制到这个克隆自git的项目文件夹里面3.查看文件状态和提交文件 在我们创建项目时&#xff0c;一般都是在本…

QAnything-1.4.01.4.1版本更新!使用指北!

久等了各位&#xff01;时隔一个多月&#xff0c;我们在4月26日和5月20日接连发布了v1.4.0和v1.4.1两个版本&#xff0c;带来了问答性能&#xff0c;解析效果等多方面的改进&#xff0c;并新增了大量的新功能和新特性 详见&#xff1a;releases 以及 使用说明 最新特性表 开发…

13-至少有5名直接下属的经理(高频 SQL 50 题基础版)

13-至少有5名直接下属的经理 select name from Employee where id in (select managerId -- 查找大于5的经理idfrom Employeegroup by managerId -- 根据id分组having count(*)>5); -- 根据分组的数据进行求个数

java连接MySQL数据库

环境准备 JDK安装 Navicat MySQL安装 下载jar包 MySQL :: Download MySQL Connector/J (Archived Versions) 创建数据库 1. 打开Navicat 2. 新建数据库 3. 定义数据库名 4. 新建查询 运行如下代码创建表log CREATE TABLE log (user VARCHAR(255) NOT NULL UNIQUE,pwd …

未见过类型题每周总结(个人向)

1.DP40 小红取数 题目 解析 一道01背包的衍生问题&#xff0c;我们可以按照它的思路定义数组dp[i][j],表示前i个数中%k为j的最大和。为什么设置未%k的最大和呢&#xff1f;是因为当两个数分别%k&#xff0c;如a%kx&#xff0c;b%ky。那么&#xff08;ab&#xff09;%k&#…