C语言minixlr如何解析XML?

99ANYc3cd6
预计阅读时长 28 分钟
位置: 首页 C语言 正文

什么是 MiniXML?

MiniXML (mxml) 是一个非常轻量级、开源的 C 语言库,用于解析和生成 XML (eXtensible Markup Language) 数据。

c语言 minixml
(图片来源网络,侵删)

它的核心特点是 “小”“简单”

  • 轻量级:代码库非常小,编译后的库文件也小,适合资源受限的环境(如嵌入式系统)。
  • 简单易用:API 设计直观,没有复杂的回调机制或复杂的对象模型,上手非常快。
  • 单文件:整个库通常只有一个 .c 文件和一个 .h 文件,极易集成到任何 C 项目中。

MiniXML 并不是一个功能齐全的 XML 解析器(像 libxml2 那样),它不支持 DTD (文档类型定义)、XML Schema 或 XPath 等高级特性,但对于简单的配置文件、数据交换等场景,它绰绰有余。


核心概念

在使用 MiniXML 之前,需要理解它的几个核心数据结构:

  1. mxml_node_t:这是 MiniXML 中最重要的结构体,代表 XML 文档中的一个节点,一个节点可以是:

    c语言 minixml
    (图片来源网络,侵删)
    • MXML_ELEMENT:元素节点,<book>
    • MXML_TEXT:文本节点,"C Programming"。
    • MXML_INTEGER:整数节点。
    • MXML_REAL:浮点数节点。
    • MXML_CUSTOM:自定义类型节点,非常灵活。
    • MXML_IGNORE:被忽略的节点。
  2. *`mxml_node_t **:所有 MiniXML 的操作都是通过指向节点的指针来完成的,XML 文档的根节点就是一个mxml_node_t *`。

  3. 节点关系:节点之间通过 childnext 指针构成树状结构。

    • child:指向第一个子节点。
    • next:指向下一个兄弟节点。

对于 XML 片段 <a><b>hello</b><c>world</c></a>

  • <a> 是根节点。
  • <b><c><a> 的子节点,也是兄弟节点。
  • "hello" 是 <b> 的子节点(文本节点)。
  • "world" 是 <c> 的子节点(文本节点)。

主要 API 函数

MiniXML 的 API 主要分为三类:加载/保存、查询、创建/修改。

c语言 minixml
(图片来源网络,侵删)

加载和保存 XML

  • mxmlLoadFile():从文件流(FILE*)加载 XML 文档,返回根节点指针。
  • mxmlLoadString():从 C 字符串加载 XML 文档,返回根节点指针。
  • mxmlSaveFile():将 XML 树保存到文件流(FILE*)。
  • mxmlSaveString():将 XML 树保存到 C 字符串(需要提供一个缓冲区)。
  • mxmlDelete()非常重要! 释放整个 XML 树占用的内存,防止内存泄漏。

查询和遍历节点

这是最常用的部分,MiniXML 提供了非常方便的查询函数。

  • mxmlFindElement():按名称查找元素节点,这是最常用的查找函数。
    // 从 parent 节点开始查找名为 "name" 的元素
    // 可以指定父节点名和兄弟节点名进行精确查找
    mxml_node_t *mxmlFindElement(mxml_node_t *parent, const char *name, const char *attr, const char *value, int descend);
  • mxmlWalkNext():遍历 XML 树,获取下一个节点。
  • mxmlGetText():从一个元素节点中获取文本内容。

创建和修改节点

  • mxmlNewElement():创建一个新的元素节点。
  • mxmlNewText():创建一个新的文本节点。
  • mxmlNewInteger():创建一个新的整数节点。
  • mxmlNewReal():创建一个新的浮点数节点。
  • mxmlLinkNode():将一个节点链接到父节点下。

实践示例

下面通过两个完整的例子来展示 MiniXML 的用法:解析(读取)生成(写入)

准备工作

你需要下载 MiniXML,它通常包含在一个名为 mxml-<version>.tar.gz 的压缩包中。 解压后,你会看到 mxml.hmxml.c 这两个核心文件。

编译方法: 在你的 C 项目中,直接将 mxml.c 和你的源文件一起编译即可。

# 编译一个名为 my_app.c 的程序
gcc my_app.c mxml.c -o my_app

示例 1:解析 XML 文件

假设我们有如下一个名为 config.xml 的配置文件:

config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <server>
    <host>192.168.1.100</host>
    <port>8080</port>
    <timeout>30</timeout>
  </server>
  <database>
    <name>myapp_db</name>
    <user>admin</user>
    <password>secret</password>
  </database>
</config>

下面的 C 程序将读取这个文件,并提取出配置信息。

parse_example.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mxml.h" // 包含 MiniXML 头文件
int main() {
    mxml_node_t *tree = NULL;
    mxml_node_t *node = NULL;
    // 1. 从文件加载 XML
    FILE *fp = fopen("config.xml", "r");
    if (fp == NULL) {
        perror("无法打开 config.xml");
        return 1;
    }
    tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
    fclose(fp);
    if (tree == NULL) {
        fprintf(stderr, "无法解析 XML 文件\n");
        return 1;
    }
    // 2. 查询并提取数据
    // 查找 <server> 节点
    node = mxmlFindElement(tree, tree, "server", NULL, NULL, MXML_DESCEND);
    if (node != NULL) {
        // 在 <server> 节点下查找 <host>
        mxml_node_t *host_node = mxmlFindElement(node, node, "host", NULL, NULL, MXML_DESCEND);
        if (host_node != NULL) {
            printf("Server Host: %s\n", mxmlGetText(host_node, 0));
        }
        // 查找 <port>
        mxml_node_t *port_node = mxmlFindElement(node, node, "port", NULL, NULL, MXML_DESCEND);
        if (port_node != NULL) {
            printf("Server Port: %s\n", mxmlGetText(port_node, 0));
        }
    }
    // 查找 <database> 节点
    node = mxmlFindElement(tree, tree, "database", NULL, NULL, MXML_DESCEND);
    if (node != NULL) {
        // 在 <database> 节点下查找 <name>
        mxml_node_t *name_node = mxmlFindElement(node, node, "name", NULL, NULL, MXML_DESCEND);
        if (name_node != NULL) {
            printf("Database Name: %s\n", mxmlGetText(name_node, 0));
        }
    }
    // 3. 释放内存
    mxmlDelete(tree);
    return 0;
}

编译与运行:

gcc parse_example.c mxml.c -o parse_example
./parse_example

预期输出:

Server Host: 192.168.1.100
Server Port: 8080
Database Name: myapp_db

示例 2:生成 XML 文件

下面的 C 程序将创建一个 XML 树,并将其写入到一个新的文件中。

generate_example.c

#include <stdio.h>
#include <stdlib.h>
#include "mxml.h"
int main() {
    mxml_node_t *xml = NULL;
    mxml_node_t *root = NULL;
    mxml_node_t *item_node = NULL;
    mxml_node_t *text_node = NULL;
    FILE *fp = NULL;
    // 1. 创建 XML 树
    // 创建根节点 <library>
    root = mxmlNewElement(NULL, "library");
    xml = root;
    // 创建第一个 <book> 节点
    item_node = mxmlNewElement(xml, "book");
    mxmlNewElement(item_node, "title");
    text_node = mxmlNewText(mxmlFindElement(item_node, item_node, "title", NULL, NULL, MXML_DESCEND), 0);
    mxmlSetText(text_node, 0, "The C Programming Language");
    mxmlNewElement(item_node, "author");
    text_node = mxmlNewText(mxmlFindElement(item_node, item_node, "author", NULL, NULL, MXML_DESCEND), 0);
    mxmlSetText(text_node, 0, "Kernighan & Ritchie");
    mxmlNewInteger(item_node, "year", 1978);
    // 创建第二个 <book> 节点
    item_node = mxmlNewElement(xml, "book");
    mxmlNewElement(item_node, "title");
    text_node = mxmlNewText(mxmlFindElement(item_node, item_node, "title", NULL, NULL, MXML_DESCEND), 0);
    mxmlSetText(text_node, 0, "Clean Code");
    mxmlNewElement(item_node, "author");
    text_node = mxmlNewText(mxmlFindElement(item_node, item_node, "author", NULL, NULL, MXML_DESCEND), 0);
    mxmlSetText(text_node, 0, "Robert C. Martin");
    mxmlNewInteger(item_node, "year", 2008);
    // 2. 将 XML 树保存到文件
    fp = fopen("library.xml", "w");
    if (fp == NULL) {
        perror("无法创建 library.xml");
        mxmlDelete(xml); // 出错前记得释放内存
        return 1;
    }
    mxmlSaveFile(fp, xml, MXML_NO_CALLBACK);
    fclose(fp);
    // 3. 释放内存
    mxmlDelete(xml);
    printf("成功生成 library.xml 文件\n");
    return 0;
}

编译与运行:

gcc generate_example.c mxml.c -o generate_example
./generate_example

生成的 library.xml 文件内容:

<?xml version="1.0"?>
<library>
  <book>The C Programming Language</title>
    <author>Kernighan &amp; Ritchie</author>
    <year>1978</year>
  </book>
  <book>Clean Code</title>
    <author>Robert C. Martin</author>
    <year>2008</year>
  </book>
</library>

MiniXML vs. libxml2

特性 MiniXML libxml2
复杂度 非常简单,API 直观 非常复杂,功能强大但学习曲线陡峭
大小 极小,单文件,易于集成 较大,依赖其他库
功能 基本的解析和生成,无高级特性 支持完整的 XML 标准(DTD, Schema, XPath, XSLT 等)
性能 对于简单任务足够 性能极高,经过高度优化
适用场景 嵌入式系统、配置文件、简单数据交换 桌面应用、Web 服务器、需要完整 XML 支持的复杂项目

MiniXML 是一个在 C 语言处理 XML 时非常出色的“瑞士军刀”,如果你需要的只是读取和写入简单的 XML 结构,并且希望项目保持轻量、易于维护,MiniXML 是你的不二之选,它的简洁性和易用性是其最大的优势。

如果你的项目需要处理复杂的 XML 规范、进行 XPath 查询或 XSLT 转换,libxml2 这样的全功能库才是更合适的选择,但对于绝大多数日常任务,MiniXML 完全够用且非常高效。

-- 展开阅读全文 --
头像
Pycharm如何配置C语言开发环境?
« 上一篇 04-21
页时间调用代码是什么?
下一篇 » 04-21

相关文章

取消
微信二维码
支付宝二维码

目录[+]