Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
xmloxide — libxml2 的纯 Rust 重新实现 | Kitploit
工具/GitHubGitHub/jonwiggins/xmloxide
静态分析漏洞分析代码分析模糊测试二进制分析学习与教育精选资源实验室与实践
GitHubjonwiggins/xmloxide

xmloxide

libxml2 的纯 Rust 重新实现

查看仓库
848752个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
# xmloxide

[![CI](https://github.com/jonwiggins/xmloxide/actions/workflows/ci.yml/badge.svg)](https://github.com/jonwiggins/xmloxide/actions/workflows/ci.yml)
[![crates.io](https://img.shields.io/crates/v/xmloxide.svg)](https://crates.io/crates/xmloxide)
[![docs.rs](https://docs.rs/xmloxide/badge.svg)](https://docs.rs/xmloxide)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![MSRV](https://img.shields.io/badge/MSRV-1.81-blue.svg)](https://www.rust-lang.org)

一个纯 Rust 实现的 [libxml2](https://gitlab.gnome.org/GNOME/libxml2) —— 开源世界中事实标准的 XML/HTML 解析库。

libxml2 于 2025 年 12 月正式停止维护,并存在已知的安全问题。xmloxide 旨在成为一个内存安全、高性能的替代方案,并通过相同的符合性测试套件。

## 特性

- **内存安全** —— 基于竞技场的树结构,公共 API 中零 `unsafe`
- **符合标准** —— W3C XML 符合性测试套件 100% 通过率(1727/1727 个适用测试)
- **错误恢复** —— 解析格式错误的 XML 仍能生成可用的树,与 libxml2 类似
- **多解析 API** —— DOM 树、SAX2 流式、XmlReader 拉取、推送/增量
- **HTML 解析器** —— 容错的 HTML 4.01 解析,支持自动闭合和空元素
- **WHATWG HTML5 解析器** —— 完整的 [HTML 生活标准](https://html.spec.whatwg.org/) 分词器和树构建器(8810/8810 个 html5lib-tests 通过)
- **HTML5 流式** —— HTML5 的 SAX 类回调 API(`html5::sax`),在不构建 DOM 树的情况下包装分词器
- **CSS 选择器** —— 使用熟悉的 CSS 语法查询元素(`css::select`),包含组合器、伪类以及快速的 `#id` 查找
- **XPath 1.0+** —— 完整的表达式解析器和求值器,包含所有 XPath 1.0 核心函数以及关键的 XPath 2.0 函数(`matches()`、`replace()`、`tokenize()`、`upper-case()`、`lower-case()`、`abs()`、`min()`、`max()` 等)
- **验证** —— DTD、RelaxNG、XML Schema (XSD) 以及 ISO Schematron (ISO/IEC 19757-3) 验证
- **Serde 集成** —— 可选的 `serde` 特性,用于 XML 与 Rust 类型之间的序列化/反序列化
- **异步解析** —— 可选的 `async` 特性,用于从 `tokio::io::AsyncRead` 源进行解析
- **标准 XML** —— C14N 1.0 和 Exclusive C14N 序列化
- **XInclude** —— 文档包含处理
- **XML 目录** —— OASIS XML 目录用于 URI 解析
- **`xmllint` CLI** —— 用于解析、验证和查询 XML 的命令行工具
- **尽可能零拷贝** —— 字符串驻留以实现快速比较
- **无全局状态** —— 每个 `Document` 都是独立的,并且是 `Send + Sync`
- **C/C++ FFI** —— 完整的 C API,包含头文件(`include/xmloxide.h`),用于嵌入 C/C++ 项目
- **最小依赖** —— 仅依赖 `encoding_rs`(库本身零其他依赖;`clap` 仅用于 CLI)

## 快速开始

```rust
use xmloxide::Document;

let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("root"));
assert_eq!(doc.text_content(root), "Hello");
```

### 序列化

```rust
use xmloxide::Document;
use xmloxide::serial::serialize;

let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let xml = serialize(&doc);
assert_eq!(xml, "<root><child>Hello</child></root>");
```

### XPath 查询

```rust
use xmloxide::Document;
use xmloxide::xpath::{evaluate, XPathValue};

let doc = Document::parse_str("<library><book><title>Rust</title></book></library>").unwrap();
let root = doc.root_element().unwrap();
let result = evaluate(&doc, root, "count(book)").unwrap();
assert_eq!(result.to_number(), 1.0);
```

### SAX2 流式

```rust
use xmloxide::sax::{parse_sax, SaxHandler, DefaultHandler};
use xmloxide::parser::ParseOptions;

struct MyHandler;
impl SaxHandler for MyHandler {
    fn start_element(&mut self, name: &str, _: Option<&str>, _: Option<&str>,
                     _: &[(String, String, Option<String>, Option<String>)]) {
        println!("Element: {name}");
    }
}

parse_sax("<root><child/></root>", &ParseOptions::default(), &mut MyHandler).unwrap();
```

### HTML 解析

```rust
use xmloxide::html::parse_html;

let doc = parse_html("<p>Hello <br> World").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("html"));
```

### CSS 选择器

```rust
use xmloxide::css::select;
use xmloxide::Document;

let doc = Document::parse_str(r#"<div><p class="intro">Hello</p><p>World</p></div>"#).unwrap();
let root = doc.root_element().unwrap();
let intros = select(&doc, root, "p.intro").unwrap();
assert_eq!(intros.len(), 1);
assert_eq!(doc.text_content(intros[0]), "Hello");
```

### HTML5 解析(WHATWG)

```rust
use xmloxide::html5::parse_html5;

let doc = parse_html5("<p>Hello <b>world</b>").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("html"));
```

也支持片段解析(`innerHTML` 背后的算法):

```rust
use xmloxide::html5::{parse_html5_with_options, Html5ParseOptions};

let opts = Html5ParseOptions {
    scripting: false,
    fragment_context: Some("body".to_string()),
};
let doc = parse_html5_with_options("<p>fragment</p>", &opts).unwrap();
```

### HTML5 流式(SAX 类似)

```rust
use xmloxide::html5::sax::{Html5SaxHandler, parse_html5_sax};

struct LinkExtractor { hrefs: Vec<String> }
impl Html5SaxHandler for LinkExtractor {
    fn start_element(&mut self, name: &str, attrs: &[(String, String)], _sc: bool) {
        if name == "a" {
            if let Some((_, href)) = attrs.iter().find(|(n, _)| n == "href") {
                self.hrefs.push(href.clone());
            }
        }
    }
}

let mut handler = LinkExtractor { hrefs: Vec::new() };
parse_html5_sax(r#"<a href="https://github.com/jonwiggins/xmloxide/blob/main/page">Link</a>"#, &mut handler);
assert_eq!(handler.hrefs, vec!["/page"]);
```

### 错误恢复

```rust
use xmloxide::parser::{parse_str_with_options, ParseOptions};

let opts = ParseOptions::default().recover(true);
let doc = parse_str_with_options("<root><unclosed>", &opts).unwrap();
for diag in &doc.diagnostics {
    eprintln!("{}", diag);
}
```

## CLI 工具

```sh
# 解析并漂亮打印
xmllint --format document.xml

# 根据 schema 验证
xmllint --schema schema.xsd document.xml
xmllint --relaxng schema.rng document.xml
xmllint --schematron schema.sch document.xml
xmllint --dtdvalid schema.dtd document.xml

# XPath 查询
xmllint --xpath "//title" document.xml

# 标准 XML
xmllint --c14n document.xml

# 解析 HTML
xmllint --html page.html
```

## 模块概览

| 模块 | 描述 |
|--------|-------------|
| `tree` | 基于竞技场的 DOM 树(`Document`、`NodeId`、`NodeKind`) |
| `parser` | XML 1.0 递归下降解析器,支持错误恢复 |
| `parser::push` | 用于分块输入的推送/增量解析器 |
| `html` | 容错的 HTML 4.01 解析器 |
| `html5` | WHATWG HTML 生活标准解析器(分词器 + 树构建器) |
| `html5::sax` | HTML5 的流式 SAX 类 API(不构建 DOM 树) |
| `css` | 用于查询文档树的 CSS 选择器引擎 |
| `sax` | SAX2 流式事件驱动解析器 |
| `reader` | XmlReader 拉取式解析 API |
| `serial` | XML、HTML 和 HTML5 序列化器,以及标准 XML (C14N) |
| `xpath` | XPath 1.0+ 表达式解析器和求值器 |
| `validation::dtd` | DTD 解析和验证 |
| `validation::relaxng` | RelaxNG 模式验证 |
| `validation::xsd` | XML Schema (XSD) 验证 |
| `validation::schematron` | ISO Schematron 基于规则的验证 |
| `serde_xml` | Serde XML 序列化/反序列化(可选 `serde` 特性) |
| `async_xml` | 通过 `tokio::io::AsyncRead` 进行异步解析(可选 `async` 特性) |
| `xinclude` | XInclude 1.0 文档包含 |
| `catalog` | OASIS XML 目录用于 URI 解析 |
| `encoding` | 字符编码检测和转码 |
| `ffi` | C/C++ FFI 绑定(`include/xmloxide.h`) |

## 性能

解析吞吐量与 libxml2 相当 —— 大多数文档相差在 3-4% 以内,且在 SVG 上 **快 12%**。得益于基于竞技场的树设计,序列化 **快 1.5-2.4 倍**。在所有基准测试中,XPath **快 1.1-2.7 倍**。

**解析:**

| 文档 | 大小 | xmloxide | libxml2 | 结果 |
|----------|------|----------|---------|--------|
| Atom 订阅源 | 4.9 KB | 26.7 µs (176 MiB/s) | 25.5 µs (184 MiB/s) | 约慢 4% |
| SVG 绘图 | 6.3 KB | 58.5 µs (103 MiB/s) | 65.6 µs (92 MiB/s) | **快 12%** |
| Maven POM | 11.5 KB | 76.9 µs (142 MiB/s) | 74.2 µs (148 MiB/s) | 约慢 4% |
| XHTML 页面 | 10.2 KB | 69.5 µs (139 MiB/s) | 61.5 µs (157 MiB/s) | 约慢 13% |
| 大文件 (374 KB) | 374 KB | 2.15 ms (169 MiB/s) | 2.08 ms (175 MiB/s) | 约慢 3% |

**序列化:**

| 文档 | 大小 | xmloxide | libxml2 | 结果 |
|----------|------|----------|---------|--------|
| Atom 订阅源 | 4.9 KB | 11.3 µs | 17.5 µs | **快 1.5 倍** |
| Maven POM | 11.5 KB | 20.1 µs | 47.5 µs | **快 2.4 倍** |
| 大文件 (374 KB) | 374 KB | 614 µs | 1397 µs | **快 2.3 倍** |

**XPath:**

| 表达式 | xmloxide | libxml2 | 结果 |
|------------|----------|---------|--------|
| 简单路径 (`//entry/title`) | 1.51 µs | 1.63 µs | **快 8%** |
| 属性谓词 (`//book[@id]`) | 5.91 µs | 15.99 µs | **快 2.7 倍** |
| `count()` 函数 | 1.09 µs | 1.67 µs | **快 1.5 倍** |
| `string()` 函数 | 1.32 µs | 1.77 µs | **快 1.3 倍** |

关键优化:基于竞技场的树实现快速序列化,用于字符验证的字节级预检查,批量文本扫描,名称解析的 ASCII 快速路径,零拷贝元素名称拆分,内联实体解析,XPath `//` 步骤融合与扩展轴融合,内联树访问器,以及子/后代轴的名称测试快速路径。

```sh
# 运行基准测试(需要 libxml2 系统库)
cargo bench --features bench-libxml2 --bench comparison_bench
```

## 测试

- **1078 个单元测试** 覆盖所有模块
- **138 个 FFI 测试** 覆盖完整的 C API 表面(包括 SAX、Schematron 和 CSS)
- **libxml2 兼容性套件** —— 119/119 个测试通过(100%),涵盖 XML 解析、命名空间、错误检测和 HTML 解析
- **W3C XML 符合性测试套件** —— 1727/1727 个适用测试通过(100%)
- **html5lib-tests** —— 7032/7032 个分词器测试 + 1778/1778 个树构建测试通过(100%)
- **集成测试** 涵盖真实的 XML/HTML 文档、边缘情况和错误恢复

```sh
cargo test --all-features
```

## C/C++ FFI

xmloxide 提供了一个 C 兼容的 API,用于嵌入 C/C++ 项目(如 Chromium、游戏引擎或任何当前使用 libxml2 的代码库)。

```sh
# 构建共享库 + 静态库(使用附带的 Makefile)
make

# 或单独构建:
make shared   # .so / .dylib / .dll
make static   # .a / .lib

# 构建并运行 C 示例
make example
```

```c
#include "xmloxide.h"

xmloxide_document *doc = xmloxide_parse_str("<root>Hello</root>");
uint32_t root = xmloxide_doc_root_element(doc);
char *name = xmloxide_node_name(doc, root);   // "root"
char *text = xmloxide_node_text_content(doc, root); // "Hello"

xmloxide_free_string(name);
xmloxide_free_string(text);
xmloxide_free_doc(doc);
```

完整的 API —— 包括树导航和修改、XPath 求值、序列化(普通和漂亮打印)、HTML/HTML5 解析、DTD/RelaxNG/XSD/Schematron 验证、C14N、SAX 流式、XmlReader、推送解析器和 XML 目录 —— 在 [`include/xmloxide.h`](https://github.com/jonwiggins/xmloxide/blob/main/include/xmloxide.h) 中声明。

## 从 libxml2 迁移

| libxml2 | xmloxide (Rust) | xmloxide (C FFI) |
|---------|----------------|------------------|
| `xmlReadMemory` | `Document::parse_str` | `xmloxide_parse_str` |
| `xmlReadFile` | `Document::parse_file` | `xmloxide_parse_file` |
| `xmlParseDoc` | `Document::parse_bytes` | `xmloxide_parse_bytes` |
| `htmlReadMemory` | `html::parse_html` | `xmloxide_parse_html` |
| (HTML5 解析) | `html5::parse_html5` | — |
| (HTML5 片段 / innerHTML) | `html5::parse_html5_with_options` | — |
| (HTML5 流式) | `html5::sax::parse_html5_sax` | — |
| (CSS 选择器 / `querySelector`) | `css::select` | — |
| `xmlFreeDoc` | (丢弃 `Document`) | `xmloxide_free_doc` |
| `xmlDocGetRootElement` | `doc.root_element()` | `xmloxide_doc_root_element` |
| `xmlNodeGetContent` | `doc.text_content(id)` | `xmloxide_node_text_content` |
| `xmlNodeSetContent` | `doc.set_text_content(id, s)` | `xmloxide_set_text_content` |
| `xmlGetProp` | `doc.attribute(id, name)` | `xmloxide_node_attribute` |
| `xmlSetProp` | `doc.set_attribute(...)` | `xmloxide_set_attribute` |
| `xmlNewNode` | `doc.create_node(...)` | `xmloxide_create_element` |
| `xmlNewText` | `doc.create_node(Text{..})` | `xmloxide_create_text` |
| `xmlAddChild` | `doc.append_child(p, c)` | `xmloxide_append_child` |
| `xmlAddPrevSibling` | `doc.insert_before(ref, c)` | `xmloxide_insert_before` |
| `xmlUnlinkNode` | `doc.remove_node(id)` | `xmloxide_remove_node` |
| `xmlCopyNode` | `doc.clone_node(id, deep)` | `xmloxide_clone_node` |
| `xmlGetID` | `doc.element_by_id(s)` | `xmloxide_element_by_id` |
| `xmlDocDumpMemory` | `serial::serialize(&doc)` | `xmloxide_serialize` |
| `xmlDocDumpFormatMemory` | `serial::serialize_with_options` | `xmloxide_serialize_pretty` |
| `htmlDocDumpMemory` | `serial::html::serialize_html` | `xmloxide_serialize_html` |
| `xmlC14NDocDumpMemory` | `serial::c14n::canonicalize` | `xmloxide_canonicalize` |
| `xmlXPathEvalExpression` | `xpath::evaluate` | `xmloxide_xpath_eval` |
| `xmlValidateDtd` | `validation::dtd::validate` | `xmloxide_validate_dtd` |
| `xmlRelaxNGValidateDoc` | `validation::relaxng::validate` | `xmloxide_validate_relaxng` |
| `xmlSchemaValidateDoc` | `validation::xsd::validate_xsd` | `xmloxide_validate_xsd` |
| (Schematron 验证) | `validation::schematron::validate_schematron` | `xmloxide_validate_schematron` |
| `xmlXIncludeProcess` | `xinclude::process_xincludes` | `xmloxide_process_xincludes` |
| `xmlLoadCatalog` | `Catalog::parse` | `xmloxide_parse_catalog` |
| `xmlSAX2...` 回调 | `sax::SaxHandler` trait | `xmloxide_sax_parse` |
| `xmlTextReaderRead` | `reader::XmlReader` | `xmloxide_reader_read` |
| `xmlCreatePushParserCtxt` | `parser::PushParser` | `xmloxide_push_parser_new` |
| `xmlParseChunk` | `PushParser::push` | `xmloxide_push_parser_push` |

**线程安全:** 与 libxml2 不同,xmloxide 没有全局状态。每个 `Document` 都是独立的,并且是 `Send + Sync`。FFI 层使用线程局部存储来存储最后一条错误消息 —— 每个线程都有自己的错误状态。无需初始化或清理函数。

## 模糊测试

xmloxide 包含用于安全测试的模糊测试目标:

```sh
# 安装 cargo-fuzz(需要 nightly)
cargo install cargo-fuzz

# 运行模糊测试目标
cargo +nightly fuzz run fuzz_xml_parse
cargo +nightly fuzz run fuzz_html_parse
cargo +nightly fuzz run fuzz_html5_parse
cargo +nightly fuzz run fuzz_html5_fragment
cargo +nightly fuzz run fuzz_xpath
cargo +nightly fuzz run fuzz_roundtrip
cargo +nightly fuzz run fuzz_sax
cargo +nightly fuzz run fuzz_reader
cargo +nightly fuzz run fuzz_push
cargo +nightly fuzz run fuzz_validation
cargo +nightly fuzz run fuzz_schematron
```

## 构建

```sh
cargo build
cargo test
cargo clippy --all-targets --all-features -- -D warnings
cargo bench
```

最低支持的 Rust 版本:**1.81**

## 限制

- **不支持 XML 1.1** —— xmloxide 仅实现 XML 1.0(第五版)。XML 1.1 很少使用且不在计划中。
- **不支持 XSLT** —— XSLT 是一个独立的规范(libxslt),不在范围内。
- **HTML 解析器** —— 同时提供了 HTML 4.01 解析器(与 libxml2 行为匹配)和完整的 WHATWG HTML5 解析器。HTML5 解析器通过了 100% 的 html5lib-tests。
- **推送解析器内部缓冲** —— 推送/增量解析器 API(`PushParser`)当前会缓冲所有推送的数据,并在 `finish()` 时执行完整解析,而不是像 libxml2 的 `xmlParseChunk` 那样真正流式处理。SAX 流式(XML 的 `parse_sax`,HTML5 的 `html5::sax::parse_html5_sax`)可作为内存受限的大文档处理的替代方案。
- **XPath `namespace::` 轴** —— 当命名空间在作用域内匹配时,`namespace::` 轴返回元素节点(而不是实例化单独的命名空间节点),遵循与属性轴相同的模式。

## 贡献

参见 [CONTRIBUTING.md](https://github.com/jonwiggins/xmloxide/blob/main/CONTRIBUTING.md) 了解开发设置和指南。

## 更新日志

参见 [CHANGELOG.md](https://github.com/jonwiggins/xmloxide/blob/main/CHANGELOG.md) 了解版本历史。

## 许可证

MIT
下载工具