admin管理员组文章数量:1399881
XML
XML - XML学习/XML文件解析器(C++)实现
XML概述
XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。它也是元标记语言,用于定义其他与特定领域有关的,语义的,结构化的标记语言的句法语言。XML与HTML一样,都来自Standard Generalized Markup Language(标准通用标记语言,SGML)
SGML是一种用标记来描述文档资料的通用语言,它包含一系列的文档类型定义(Document Type Definition,DTD),DTD中定义了标记的含义,因而SGML的语法是可以拓展的。SGML十分庞大,不容易学习,也不容易使用,在计算机上实现也十分困难。
HTML只实现了SGML中很少的一部分标记,它的标记是固定的,语法也是不可拓展的,但是由于它语法的固定使得它简单易学,随着Web技术的发展而推广到全世界,但是由于HTML过于简单,且没有固定的格式,在发展的过程中遇到了一些问题,此时XML便应运而生。
XML的特点
- 简介有效
- XML是一个精简的SGML,它将SGML的丰富功能与HTML的易用性结合到Web应用中,保留了SGML的可拓展功能,这使得XML从根本上区别于HTML
- 易学易用
- 开放的国际化标准
- XML标准。W3C正式批准的标准,这意味着这个标准是稳定的,完全可用于Web和工具的开发
- XML名域标准。
- DOM(Document Object Model,文档对象模型)标准。为给结构化的数据编写脚本提供标准,这样,开发人员就能够与计算机在基于XML的数据上进行交互
- XSL标准。XSL有两个模块:XSL转换语言和XSL格式化对象。
- XLL标准和XML指针语言(XPointer)标准。
- 高效且可扩充
- XML支持复用文档片断,使用者可以发明和使用自己的标签,也可与他人共享,可延伸性大。
总结:XML使用一个简单而又灵活的标准格式,为基于Web的应用提供一个描述数据和交换数据的有效手段。HTML描述了显示全球数据的通用方法,而XML提供了直接处理全球数据的通用方法。
XML的作用
XML让信息的提供者可以根据需要,自行定义标记及属性名,结构化地描述信息内容
- 使得搜索更加有意义
- 开发灵活的Web应用软件
- XML的应用使得三层Web应用软件的开发更加简单,由于其能够有效地进行消息和数据标准的统一,从而设计,开发出更加灵活的Web应用软件
- 实现不同数据的集成
- 使用于多种应用环境
- 客户端数据处理与计算
- 数据显示多样化
- 局部数据更新
- 与现有Web发布机制相兼容
- 可升级性
- 压缩性能高
- XML压缩性能很好,因为用于描述数据结构的标签可以重复使用。
XML的应用
- 应用于客户需要与不同的数据源进行交互时
- 应用于将大量运算负荷分布在客户端
- 应用于将同一数据以不同的面貌展现给不同的用户
- 应用于网络代理对所取得的信息进行编辑,增减以适应个人用户的需要
解析XML
一个实用的XML文档必须满足两点,分别是 组织良好(Well-formed) 和 有效(Valid)
XML文档
一个组织良好的XML文档,需要满足以下三项基本规则:
- 文档以XML定义
<? xml version = "1.0" ?>
开始 - 有一个包含所有其他内容的根元素
- 所有元素必须合理地嵌套,不允许交叉嵌套
实例XML文件
<?xml version="1.0" encoding="UTF-8"?>
<students><student><id>202021091138</id><name>wzh</name></student>
</students>
DOM解析
文档对象模型为XML文档的解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用DOM接口来操作这个树结构。
DOM提供了一组丰富的功能,用户可以使用这些功能来解释和操作XML文档,但是DOM解释XML文档也会遇到一些挑战和问题:
- DOM构建整个文档驻留内存的树。如果文档很大时,就会要求有极大的内存,这消耗的内存往往是XML文档的10~100倍左右
- DOM创建表示原始文档中每个东西的对象,包括元素,文本,属性和空格。如果用户只关注原始文档的一小部分,那么创建那些永远不被使用的对象是极其浪费的
- DOM解析器必须在代码取得控制权之前读取整个文档。对于非常大的文档,这会引起显著的延迟
总结:除去以上的问题,DOM API是解析XML文档非常有用的方法
SAX解析
SAX接口的出现是为了解决DOM解析XML文件面临的一些问题,SAX接口有如下特征:
- SAX解析器向代码发送事件。当解析器发现元素开始,元素结束,文本,文档的开始或结束时,它会告诉用户。
- SAX解析器根本不创建任何对象,它只是将事件传递给应用程序。如果希望基于哪些事件创建对象,这将由编程者自己来完成
- SAX解析器在解析开始的时候就开始发送事件。当解析器发现文档开始,元素开始和文本时,代码会收到一个事件。应用程序可以立即开始生成结果;不必一直等到整个文档被解析完毕。
当然,SAX解析器也有一些不足点:
- SAX事件是无状态的。当SAX解析器在XML文档中发现文本时,它就向代码发送一个事件。该事件仅给用户发现的文本,它不告诉用户什么元素包含那个文本。如果想了解这一点,则用户必须自己编写状态管理代码
- SAX事件不是持久的。如果应用程序需要一个数据结构来对XML文档建模,则必须自己编写那样的代码。如果需要从SAX事件访问数据,并且没有把那个数据存储在代码中,那么用户不得不再次解析该文档
以上是解析XML文档主要使用的2种方法,DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点),可以遍历和修改节点,SAX解析器逐行扫描文档,一遍扫描一遍解析。相比于DOM,SAX可以在解析文档的任意时刻停止解析解析,是一种速度更快,更高效的方法。
JDOM解析
JDOM是基于Java技术的开发源码项目,它试图遵循80/20原则:用DOM和SAX的20%的功能来满足80%的用户需求。JDOM的底层还是使用SAX和DOM解析器
JDOM的主要特征是它极大地减少了用户必须编写的代码数量,JDOM的应用程序的程度通常是DOM应用程序的1/3,大约是SAX应用程序的一半。JDOM并不做所有的事情,只满足大多数用户要做的解析需求
JAXP解析
JAXP出现是SUN公司为了弥补JAVA在XML标准制定上的空白而制定的一套JAVA XML标准API。它并没有为JAVA解析XML提供任何新功能,但是它为在JAVA获取SAX与DOM解析器提供了更加直接的途径。
它封装了sax\dom两种接口,并在sax\dom的基础之上,作了一套比较简单的api以供开发。
XML文件解析器设计与实现(C++)
造轮子!造轮子!
XML文件解析器实现代码参考来源:
XML文件解析器用法
- 从文件加载XML
- 从字符串加载XML
- 访问节点:根据数组下标,节点名称
- 遍历节点:数组,迭代器,for in
- 添加节点
- 删除节点
- 获取,修改节点名称
- 获取,删除节点属性
- 获取,修改节点内容
XML解析器具体实现
XML文件解析器具体实现取决于xml类和Parser类,在xml.h文件中,增加了一个Value数值转化类,方便于XML节点属性的自动转化
xml.h文件
#pragma once#include <string>
#include <list>
#include <map>
using namespace std;namespace wzh {namespace xml {class Value {// 数值转化类public:Value();Value(bool value);Value(int value);Value(double value);Value(const char * value);Value(const string & value);~Value();Value & operator = (bool value);Value & operator = (int value);Value & operator = (double value);Value & operator = (const char * value);Value & operator = (const string & value);Value & operator = (const Value & value);bool operator == (const Value & other);bool operator != (const Value & other);operator bool();operator int();operator double();operator string();private:string m_value;};class XML {public:XML();XML(const char * name);XML(const string & name);XML(const XML & other);string name() const; // 获取节点名称void setName(const string & name); // 设置节点名称string text() const; // 获取节点内容void setText(const string & text); // 设置节点内容Value & attr(const string & key); // 获取节点属性void setAttr(const string & key, const Value & val); // 设置节点属性string str() const; // 返回属性序列化结果void clear(); // 释放内存void append(const XML & child); // 添加子节点XML & operator [] (int index); // 以数组下标方式获取子节点XML & operator [] (const char * name); // 通过节点名称获取子节点(支持C形式)XML & operator [] (const string & name); // 通过节点名称获取子节点(支持C++形式)XML & operator = (const XML & other);void remove(int index); // 以数组下标方式删除子节点void remove(const char * name); // 通过节点名称删除子节点(支持C形式)void remove(const string & name); // 通过节点名称删除子节点(支持C++形式)typedef std::list<XML>::iterator iterator;iterator begin() {return m_child->begin();}iterator end() {return m_child->end();}iterator erase(iterator it) {it->clear();return m_child->erase(it);}int size() const {return m_child->size();}bool load(const string & filename);bool save(const string & filename);bool parse(const string & str);private:// 使用指针加快数据的读取以及存储开销string* m_name; // 节点名称string* m_text; // 节点内容std::map<string, Value>* m_attrs; // 节点属性std::list<XML>* m_child; // 子节点};}
}
xml.cpp文件
#include "xml.h"
#include "Parser.h"
using namespace wzh::xml;#include <fstream>
#include <sstream>
using namespace std;Value::Value() {
}Value::Value(bool value) {*this = value;
}Value::Value(int value) {*this = value;
}Value::Value(double value) {*this = value;
}Value::Value(const char * value) : m_value(value) {
}Value::Value(const string & value) : m_value(value) {
}Value::~Value() {
}Value & Value::operator = (bool value) {m_value = value ? "true" : "false";return *this;
}Value & Value::operator = (int value) {stringstream ss;ss << value;m_value = ss.str();return *this;
}Value & Value::operator = (double value) {stringstream ss;ss << value;m_value = ss.str();return *this;
}Value & Value::operator = (const char * value) {m_value = value;return *this;
}Value & Value::operator = (const string & value) {m_value = value;return *this;
}Value & Value::operator = (const Value & value) {m_value = value.m_value;return *this;
}bool Value::operator == (const Value & other) {return m_value == other.m_value;
}bool Value::operator != (const Value & other) {return !(m_value == other.m_value);
}Value::operator bool() {if (m_value == "true")return true;else if (m_value == "false")return false;return false;
}Value::operator int() {return std::atoi(m_value.c_str());
}Value::operator double() {return std::atof(m_value.c_str());
}Value::operator string() {return m_value;
}XML::XML() : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {}XML::XML(const char * name) : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {m_name = new string(name);
}XML::XML(const string & name) : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {m_name = new string(name);
}XML::XML(const XML & other) {m_name = other.m_name;m_text = other.m_text;m_attrs = other.m_attrs;m_child = other.m_child;
}string XML::name() const {if(m_name == nullptr) {return "";}return *m_name;
}void XML::setName(const string & name) {if(m_name != nullptr) {delete m_name;m_name = nullptr;}m_name = new string(name);
}string XML::text() const {if(m_text == nullptr) {return "";}return *m_text;
}void XML::setText(const string & text) {if(m_text != nullptr) {delete m_text;m_text = nullptr;}m_text = new string(text);
}Value & XML::attr(const string & key) {if(m_attrs == nullptr) {m_attrs = new std::map<string, Value>();}return (*m_attrs)[key];
}void XML::setAttr(const string & key, const Value & val) {if(m_attrs == nullptr) {m_attrs = new std::map<string, Value>();}(*m_attrs)[key] = val;
}string XML::str() const {if(m_name == nullptr) {throw std::logic_error("element name is empty");}stringstream ss;ss << "<";ss << *m_name;if(m_attrs != nullptr) {for(auto it = m_attrs->begin(); it != m_attrs->end(); it++) {ss << " " << it->first << "=\"" << (string)it->second << "\"";}}ss << ">";if(m_child != nullptr) {for(auto it = m_child->begin(); it != m_child->end(); it++) {ss << it->str();}}if(m_text != nullptr) {ss << *m_text;}ss << "</" << *m_name << ">";return ss.str();
}void XML::clear() {if(m_name != nullptr) {delete m_name;m_name = nullptr;}if(m_text != nullptr) {delete m_text;m_text = nullptr;}if(m_attrs != nullptr) {delete m_attrs;m_attrs = nullptr;}if(m_child != nullptr) {for(auto it = m_child->begin(); it != m_child->end(); it++) {it -> clear();}delete m_child;m_child = nullptr;}
}void XML::append(const XML & child) {if(m_child == nullptr) {m_child = new std::list<XML>();}m_child->push_back(child);
}XML & XML::operator [] (int index) {if(index < 0) {throw std::logic_error("index less than zero");}if(m_child == nullptr) {m_child = new std::list<XML>();}int size = m_child->size();if(index >= 0 && index < size) {auto it = m_child->begin();for(int i=0; i<index; i++)it++;return *it;}if (index >= size) {for(int i=size; i<=index; i++)m_child->push_back(XML());}return m_child->back();
}XML & XML::operator [] (const char * name) {return (*this)[string(name)];
}XML & XML::operator [] (const string & name) {if(m_child == nullptr) {m_child = new std::list<XML>();}for(auto it = m_child->begin(); it != m_child->end(); it++) {if(it->name() == name) {return *it;}}m_child->push_back(XML(name));return m_child->back();
}XML & XML::operator = (const XML & other) {clear();m_name = other.m_name;m_text = other.m_text;m_attrs = other.m_attrs;m_child = other.m_child;return *this;
}void XML::remove(int index) {if(m_child == nullptr) {return;}int size = m_child->size();if(index < 0 || index >= size) {throw std::logic_error("index out of range");return;}auto it = m_child->begin();for(int i=0; i<index; i++) {it++;}it->clear();m_child->erase(it);
}void XML::remove(const char * name) {remove(string(name));
}void XML::remove(const string & name) {if(m_child == nullptr) {return;}for(auto it = m_child->begin(); it != m_child->end();) {if(it->name() == name) {it->clear();it = m_child->erase(it);}else {it++;}}
}bool XML::load(const string & filename)
{Parser p;if (!p.load_file(filename)){return false;}*this = p.parse();return true;
}bool XML::save(const string & filename)
{ofstream fout(filename);if (fout.fail()){return false;}fout << str();fout.close();return true;
}bool XML::parse(const string & str)
{Parser p;if (!p.load_string(str)){return false;}*this = p.parse();return true;
}
Parser.h文件
#pragma once#include "xml.h"
#include <string>
using namespace std;namespace wzh {namespace xml{class Parser {public:Parser();bool load_file(const string & file);bool load_string(const string & str);XML parse(); // 解析方法private:void skip_white_space(); // 忽略空白符bool parse_declaration(); // 解析声明bool parse_comment(); // 解析注释XML parse_element(); // 解析主函数string parse_element_name(); // 解析节点名称string parse_element_text(); // 解析节点文本string parse_element_attr_key(); // 解析节点属性string parse_element_attr_val(); // 解析节点属性值private:string m_str;int m_idx;};}
}
Parser.cpp文件
#include "Parser.h"
using namespace wzh::xml;#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;Parser::Parser() : m_str(""), m_idx(0) {
}bool Parser::load_string(const string & str) {m_str = str;m_idx = 0;return true;
}bool Parser::load_file(const string & filename) {ifstream fin(filename);if(fin.fail()) {return false;}stringstream ss;ss << fin.rdbuf();m_str = ss.str();m_idx = 0;return true;
}void Parser::skip_white_space() {while(m_str[m_idx] == ' ' || m_str[m_idx] == '\r' || m_str[m_idx] == '\n' || m_str[m_idx] == '\t') {m_idx++;}
}XML Parser::parse() {skip_white_space();if(m_str.compare(m_idx, 5, "<?xml") == 0) {if(!parse_declaration()) {throw std::logic_error("parse declaration error");}}skip_white_space();while(m_str.compare(m_idx, 4, "<!--") == 0) {if(!parse_comment()) {throw std::logic_error("parse comment error");}skip_white_space();}if (m_str[m_idx] == '<' && (isalpha(m_str[m_idx+1]) || m_str[m_idx+1] == '_')) {return parse_element();}throw std::logic_error("parse element error");
}bool Parser::parse_declaration() {if(m_str.compare(m_idx, 5, "<?xml") != 0) {return false;}m_idx += 5;size_t pos = m_str.find("?>", m_idx);if(pos == std::string::npos) {return false;}m_idx = pos + 2;return true;
}bool Parser::parse_comment() {if(m_str.compare(m_idx, 4, "<!--") != 0) {return false;}m_idx += 4;size_t pos = m_str.find("-->", m_idx);if(pos == std::string::npos) {return false;}m_idx = pos + 3;return true;
}XML Parser::parse_element() {XML elem;m_idx++;skip_white_space();const string & name = parse_element_name();elem.setName(name);while(m_str[m_idx] != '\0') {skip_white_space();if(m_str[m_idx] == '/') {if(m_str[m_idx+1] == '>') {m_idx += 2;break;}else {throw logic_error("xml empty element is error");}}else if(m_str[m_idx] == '>') {m_idx++;string text = parse_element_text();if(text != "") {elem.setText(text);}}else if(m_str[m_idx] == '<') {if(m_str[m_idx+1] == '/') {// 标签string end_tag = "</" + name + ">";size_t pos = m_str.find(end_tag, m_idx);if (pos == std::string::npos) {throw std::logic_error("xml element " + name + " end tag not found");}m_idx = (pos + end_tag.size());break;}else if (m_str.compare(m_idx, 4, "<!--") == 0) {// 注释if (!parse_comment()) {throw std::logic_error("xml comment is error");}}else {// 子节点elem.append(parse_element());}}else {// 节点属性string key = parse_element_attr_key();skip_white_space();if (m_str[m_idx] != '='){throw std::logic_error("xml element attr is error" + key);}m_idx++;skip_white_space();string val = parse_element_attr_val();elem.setAttr(key, val);}}return elem;
}string Parser::parse_element_name() {int pos = m_idx;if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) {m_idx++;while (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':') || (m_str[m_idx] == '.')) {m_idx++;}}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_text() {int pos = m_idx;while (m_str[m_idx] != '<') {m_idx++;}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_attr_key() {int pos = m_idx;if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) {m_idx++;while (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':')) {m_idx++;}}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_attr_val() {if (m_str[m_idx] != '"') {throw std::logic_error("xml element attr value should be in double quotes");}m_idx++;int pos = m_idx;while (m_str[m_idx] != '"') {m_idx++;}m_idx++;return m_str.substr(pos, m_idx - pos - 1);
}
Makefile
#指定编译器
CC = g++#找出当前目录下,所有的源文件(以.cpp结尾)
SRCS := $(shell find ./* -type f | grep '\.cpp' | grep -v 'main\.cpp')
$(warning SRCS is ${SRCS})#确定cpp源文件对应的目标文件
OBJS := $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS)))
$(warning OBJS is ${OBJS})#编译选项
CFLAGS = -g -O2 -Wall -Werror -Wno-unused -ldl -fPIC -std=c++11
$(warning CFLAGS is ${CFLAGS})#找出当前目录下所有的头文件
INCLUDE_TEMP = $(shell find ./* -type d)
INCLUDE = $(patsubst %,-I %, $(INCLUDE_TEMP))
$(warning INCLUDE is ${INCLUDE})SRC_MAIN = main.cpp
OBJ_MAIN = ${SRC_MAIN:%.cpp=%.o}
EXE_MAIN = maintarget: ${EXE_MAIN}$(EXE_MAIN): $(OBJ_MAIN) $(OBJS)$(CC) -o $@ $^ $(CFLAGS) $(INCLUDE)clean:rm -f ${OBJS} ${OBJ_MAIN} ${EXE_MAIN}%.o: %.cpp${CC} ${CFLAGS} ${INCLUDE} -c $< -o $@
附上xml测试文件
test1.xml(Maven配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.item</groupId><artifactId>servlet_mybatis</artifactId><version>1.0-SNAPSHOT</version><name>servlet_mybatis</name><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.source>1.8</maven.compiler.source><junit.version>5.7.1</junit.version></properties><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.10</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.13</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.3.1</version></plugin></plugins><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources></build>
</project>
test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<students><student id="1" class="101"><name>Jack</name><age>21</age><gender>male</gender></student><student id="2" class="102"><name>Lucy</name><age>22</age><gender>female</gender></student><student id="3" class="103"><name>Lily</name><age>23</age><gender>female</gender></student>
</students>
测试结果如下:
本文标签: XML
版权声明:本文标题:XML 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1687089713a62663.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论