Rust HTML5解析库html5gum的使用:高效、安全的HTML5标记解析与处理
Rust HTML5解析库html5gum的使用:高效、安全的HTML5标记解析与处理
html5gum是一个符合WHATWG标准的HTML tokenizer。
基本使用示例
use std::fmt::Write;
use html5gum::{Tokenizer, Token};
let html = "<title >hello world</title>";
let mut new_html = String::new();
for Ok(token) in Tokenizer::new(html) {
match token {
Token::StartTag(tag) => {
write!(new_html, "<{}>", String::from_utf8_lossy(&tag.name)).unwrap();
}
Token::String(hello_world) => {
write!(new_html, "{}", String::from_utf8_lossy(&hello_world)).unwrap();
}
Token::EndTag(tag) => {
write!(new_html, "</{}>", String::from_utf8_lossy(&tag.name)).unwrap();
}
_ => panic!("unexpected input"),
}
}
assert_eq!(new_html, "<title>hello world</title>");
API特性
html5gum提供了多种API:
- 如上所示迭代tokens
- 实现您自己的Emitter以获得最大性能
- 基于回调的API,在便利性和性能之间取得平衡
- 通过tree-builder功能,可以与html5ever和scraper集成
完整示例代码
use std::fmt::Write;
use html5gum::{Tokenizer, Token};
fn main() {
// 示例HTML内容
let html = r#"
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Hello World</h1>
<p>This is a test paragraph.</p>
<div class="container">
<span>Nested element</span>
</div>
</body>
</html>
"#;
// 创建新的字符串来存储格式化后的HTML
let mut formatted_html = String::new();
// 创建Tokenizer实例并处理每个token
for token_result in Tokenizer::new(html) {
match token_result {
Ok(token) => {
match token {
Token::StartTag(tag) => {
// 处理开始标签
write!(formatted_html, "<{}", String::from_utf8_lossy(&tag.name)).unwrap();
// 处理属性
for attr in tag.attributes {
write!(
formatted_html,
" {}=\"{}\"",
String::from_utf8_lossy(&attr.name),
String::from_utf8_lossy(&attr.value)
).unwrap();
}
write!(formatted_html, ">").unwrap();
}
Token::EndTag(tag) => {
// 处理结束标签
write!(formatted_html, "</{}>", String::from_utf8_lossy(&tag.name)).unwrap();
}
Token::String(text) => {
// 处理文本内容
write!(formatted_html, "{}", String::from_utf8_lossy(&text)).unwrap();
}
Token::Comment(comment) => {
// 处理注释
write!(formatted_html, "<!--{}-->", String::from_utf8_lossy(&comment)).unwrap();
}
Token::Doctype(doctype) => {
// 处理DOCTYPE声明
write!(formatted_html, "<!DOCTYPE html>").unwrap();
}
_ => {
// 忽略其他类型的token
}
}
}
Err(e) => {
eprintln!("Error tokenizing HTML: {:?}", e);
}
}
}
// 输出格式化后的HTML
println!("Formatted HTML:\n{}", formatted_html);
}
Tokenizer的功能与限制
html5gum完全实现了WHATWG HTML规范的13.2.5节,能够tokenize HTML文档并通过html5lib的tokenizer测试套件。作为tokenizer,这意味着:
- html5gum不实现字符集检测。该实现接受并返回字节,但假定为UTF-8。它能优雅地从无效UTF-8中恢复
- html5gum不纠正错位的标签
- html5gum不实现DOM,在HTML规范中,DOM构造(“树构建”)会影响tokenization的方式
- html5gum通常不符合WHATWG规范中的浏览器级HTML解析器标准
其他特性
- 不使用unsafe Rust
- 唯一依赖是jetscii,可以通过crate特性禁用
许可证
MIT许可证
1 回复
Rust HTML5解析库html5gum的使用:高效、安全的HTML5标记解析与处理
简介
html5gum是一个用Rust编写的HTML5解析库,专注于提供高效且符合标准的HTML5解析功能。它具有以下特点:
- 完全符合HTML5规范
- 高性能解析
- 内存安全(得益于Rust的所有权系统)
- 支持Tokenizer和Tree Builder两种解析模式
- 良好的错误恢复能力
安装
在Cargo.toml中添加依赖:
[dependencies]
html5gum = "0.2"
基本使用方法
1. 简单Tokenizer使用
use html5gum::{Tokenizer, Token};
let html = "<div>Hello, world!</div>";
let mut tokenizer = Tokenizer::new(html).infallible();
for token in tokenizer {
match token {
Token::StartTag(tag) => println!("Start tag: {}", tag.name),
Token::EndTag(tag) => println!("End tag: {}", tag.name),
Token::Text(text) => println!("Text: {}", text),
_ => {} // 忽略其他类型的token
}
}
2. 带错误处理的Tokenizer
use html5gum::{Tokenizer, Token, Error};
let html = "<div>Invalid<html>";
let mut tokenizer = Tokenizer::new(html);
while let Some(result) = tokenizer.next() {
match result {
Ok(token) => {
// 处理token
println!("Token: {:?}", token);
}
Err(e) => {
// 处理错误
eprintln!("Error: {:?}", e);
}
}
}
3. 使用Tree Builder构建DOM树
use html5gum::{Tokenizer, TreeBuilder, DefaultTree};
let html = r#"
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello</h1>
</body>
</html>
"#;
let tree: DefaultTree = TreeBuilder::new().parse(html).unwrap();
// 遍历DOM树
for node in tree.traverse() {
println!("Node: {:?}", node);
}
高级功能
1. 自定义状态处理
use html5gum::{Tokenizer, State, TokenizerOptions};
let html = "<div>Custom state</div>";
let options = TokenizerOptions {
initial_state: Some(State::Data),
..Default::default()
};
let mut tokenizer = Tokenizer::new_with_options(html, options).infallible();
for token in tokenizer {
println!("Token: {:?}", token);
}
2. 处理属性
use html5gum::{Tokenizer, Token};
let html = r#"<a href="https://example.com" target="_blank">Link</a>"#;
let mut tokenizer = Tokenizer::new(html).infallible();
for token in tokenizer {
if let Token::StartTag(tag) = token {
println!("Tag name: {}", tag.name);
for attr in tag.attributes {
println!("Attribute: {}='{}'", attr.name, attr.value);
}
}
}
3. 处理注释和DOCTYPE
use html5gum::{Tokenizer, Token};
let html = r#"<!-- comment --><!DOCTYPE html><html></html>"#;
let mut tokenizer = Tokenizer::new(html).infallible();
for token in tokenizer {
match token {
Token::Comment(comment) => println!("Comment: {}", comment),
Token::Doctype(doctype) => println!("Doctype: {:?}", doctype),
_ => {}
}
}
性能提示
- 对于不需要错误处理的场景,使用
infallible()
可以获得更好的性能 - 如果只需要部分解析结果,可以考虑提前终止解析
- 重用Tokenizer实例可以避免重复分配内存
错误处理
html5gum提供了详细的错误信息:
use html5gum::{Tokenizer, Error};
let html = "<div><invalid";
let mut tokenizer = Tokenizer::new(html);
while let Some(result) = tokenizer.next() {
match result {
Ok(token) => println!("Token: {:?}", token),
Err(Error::ParseError(e)) => {
eprintln!("Parse error at {}:{} - {}", e.position.line, e.position.column, e.kind)
},
Err(e) => eprintln!("Other error: {:?}", e),
}
}
完整示例
下面是一个完整的html5gum使用示例,展示了如何解析HTML并提取特定信息:
use html5gum::{Tokenizer, Token, Error, TreeBuilder, DefaultTree};
fn main() {
// 示例1: 简单Tokenizer使用
println!("=== 简单Tokenizer示例 ===");
let html_simple = "<div class='container'><p>Hello</p><p>World</p></div>";
let mut tokenizer = Tokenizer::new(html_simple).infallible();
for token in tokenizer {
match token {
Token::StartTag(tag) => println!("发现开始标签: {}", tag.name),
Token::EndTag(tag) => println!("发现结束标签: {}", tag.name),
Token::Text(text) => println!("发现文本内容: {}", text),
_ => {}
}
}
// 示例2: 带错误处理的解析
println!("\n=== 带错误处理的示例 ===");
let html_with_errors = "<div><p>Hello</invalid>";
let mut tokenizer_with_errors = Tokenizer::new(html_with_errors);
while let Some(result) = tokenizer_with_errors.next() {
match result {
Ok(token) => println!("解析到的Token: {:?}", token),
Err(Error::ParseError(e)) => {
eprintln!("解析错误: 行 {} 列 {} - {}", e.position.line, e.position.column, e.kind)
},
Err(e) => eprintln!("其他错误: {:?}", e),
}
}
// 示例3: 构建DOM树
println!("\n=== DOM树构建示例 ===");
let html_dom = r#"
<!DOCTYPE html>
<html>
<head>
<title>示例页面</title>
</head>
<body>
<h1>标题</h1>
<p>段落内容</p>
</body>
</html>
"#;
let tree: DefaultTree = TreeBuilder::new().parse(html_dom).unwrap();
println!("DOM树节点数: {}", tree.nodes().count());
for node in tree.traverse() {
println!("节点: {:?}", node);
}
}
总结
html5gum是一个功能强大且符合标准的HTML5解析库,适合需要高效、安全解析HTML的场景。无论是简单的文本提取还是完整的DOM树构建,html5gum都能提供良好的支持。