XML - XML学习/XML文件解析器(C++)实现

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的特点
  1. 简介有效
    • XML是一个精简的SGML,它将SGML的丰富功能与HTML的易用性结合到Web应用中,保留了SGML的可拓展功能,这使得XML从根本上区别于HTML
  2. 易学易用
  3. 开放的国际化标准
    • XML标准。W3C正式批准的标准,这意味着这个标准是稳定的,完全可用于Web和工具的开发
    • XML名域标准。
    • DOM(Document Object Model,文档对象模型)标准。为给结构化的数据编写脚本提供标准,这样,开发人员就能够与计算机在基于XML的数据上进行交互
    • XSL标准。XSL有两个模块:XSL转换语言和XSL格式化对象。
    • XLL标准和XML指针语言(XPointer)标准。
  4. 高效且可扩充
    • XML支持复用文档片断,使用者可以发明和使用自己的标签,也可与他人共享,可延伸性大。

总结:XML使用一个简单而又灵活的标准格式,为基于Web的应用提供一个描述数据和交换数据的有效手段。HTML描述了显示全球数据的通用方法,而XML提供了直接处理全球数据的通用方法。

XML的作用

​ XML让信息的提供者可以根据需要,自行定义标记及属性名,结构化地描述信息内容

  1. 使得搜索更加有意义
  2. 开发灵活的Web应用软件
    • XML的应用使得三层Web应用软件的开发更加简单,由于其能够有效地进行消息和数据标准的统一,从而设计,开发出更加灵活的Web应用软件
  3. 实现不同数据的集成
  4. 使用于多种应用环境
  5. 客户端数据处理与计算
  6. 数据显示多样化
  7. 局部数据更新
  8. 与现有Web发布机制相兼容
  9. 可升级性
  10. 压缩性能高
    • XML压缩性能很好,因为用于描述数据结构的标签可以重复使用。
XML的应用
  1. 应用于客户需要与不同的数据源进行交互时
  2. 应用于将大量运算负荷分布在客户端
  3. 应用于将同一数据以不同的面貌展现给不同的用户
  4. 应用于网络代理对所取得的信息进行编辑,增减以适应个人用户的需要

解析XML

​ 一个实用的XML文档必须满足两点,分别是 组织良好(Well-formed)有效(Valid)

XML文档

一个组织良好的XML文档,需要满足以下三项基本规则:

  1. 文档以XML定义 <? xml version = "1.0" ?> 开始
  2. 有一个包含所有其他内容的根元素
  3. 所有元素必须合理地嵌套,不允许交叉嵌套

实例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文档也会遇到一些挑战和问题:

  1. DOM构建整个文档驻留内存的树。如果文档很大时,就会要求有极大的内存,这消耗的内存往往是XML文档的10~100倍左右
  2. DOM创建表示原始文档中每个东西的对象,包括元素,文本,属性和空格。如果用户只关注原始文档的一小部分,那么创建那些永远不被使用的对象是极其浪费的
  3. DOM解析器必须在代码取得控制权之前读取整个文档。对于非常大的文档,这会引起显著的延迟

总结:除去以上的问题,DOM API是解析XML文档非常有用的方法

SAX解析

​ SAX接口的出现是为了解决DOM解析XML文件面临的一些问题,SAX接口有如下特征:

  1. SAX解析器向代码发送事件。当解析器发现元素开始,元素结束,文本,文档的开始或结束时,它会告诉用户。
  2. SAX解析器根本不创建任何对象,它只是将事件传递给应用程序。如果希望基于哪些事件创建对象,这将由编程者自己来完成
  3. SAX解析器在解析开始的时候就开始发送事件。当解析器发现文档开始,元素开始和文本时,代码会收到一个事件。应用程序可以立即开始生成结果;不必一直等到整个文档被解析完毕。

​ 当然,SAX解析器也有一些不足点:

  1. SAX事件是无状态的。当SAX解析器在XML文档中发现文本时,它就向代码发送一个事件。该事件仅给用户发现的文本,它不告诉用户什么元素包含那个文本。如果想了解这一点,则用户必须自己编写状态管理代码
  2. 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文件解析器实现代码参考来源:https://github.com/oldjun/yazi-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 = main

target: ${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="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.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>

测试结果如下:

在这里插入图片描述

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
XML文件解析可以用许多编程语言实现,包括C语言。下面是一个简单的C程序,可以读取和解析XML文件。 1. 首先需要引入标准头文件和libxml2库文件: ``` #include <stdio.h> #include <libxml/parser.h> #include <libxml/tree.h> ``` 2. 然后定义一个函数,用来读取XML文件并解析: ``` void parse_xml_file(const char* filename) { xmlDocPtr doc; xmlNodePtr cur; doc = xmlParseFile(filename); if (doc == NULL) { fprintf(stderr, "Failed to parse XML file %s\n", filename); return; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr, "Empty XML file %s\n", filename); xmlFreeDoc(doc); return; } if (xmlStrcmp(cur->name, (const xmlChar *)"root")) { fprintf(stderr, "Invalid XML file %s, root node not found\n", filename); xmlFreeDoc(doc); return; } cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) { xmlChar* key = xmlGetProp(cur, (const xmlChar *)"key"); xmlChar* value = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); printf("Key: %s, Value: %s\n", key, value); xmlFree(key); xmlFree(value); } cur = cur->next; } xmlFreeDoc(doc); } ``` 3. 最后在主函数中调用该函数,并传入要解析的XML文件名: ``` int main() { const char* filename = "example.xml"; parse_xml_file(filename); return 0; } ``` 在这个例子中,XML文件的格式如下: ``` <root> <node key="key1">value1</node> <node key="key2">value2</node> </root> ``` 解析XML文件后,程序将输出: ``` Key: key1, Value: value1 Key: key2, Value: value2 ``` 这就完成了一个简单的XML文件解析程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值