Rust语法分析库tree-sitter-css的使用:高效解析和操作CSS的Tree-sitter绑定
Rust语法分析库tree-sitter-css的使用:高效解析和操作CSS的Tree-sitter绑定
tree-sitter-css 是 Tree-sitter 的 CSS 语法分析器,它提供了高效的 CSS 解析能力。
安装
在你的项目目录中运行以下 Cargo 命令:
cargo add tree-sitter-css
或者在 Cargo.toml 中添加:
tree-sitter-css = "0.23.2"
使用示例
下面是一个完整的示例,展示如何使用 tree-sitter-css 解析 CSS 代码:
use tree_sitter::Parser;
use tree_sitter_css::language;
fn main() {
// 创建解析器
let mut parser = Parser::new();
// 设置 CSS 语言
parser.set_language(language()).expect("Error loading CSS grammar");
// 要解析的 CSS 代码
let css_code = r#"
body {
font-family: Arial, sans-serif;
color: #333;
margin: 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
"#;
// 解析 CSS
let tree = parser.parse(css_code, None).unwrap();
// 获取根节点
let root_node = tree.root_node();
// 打印语法树
println!("{}", root_node.to_sexp());
// 遍历规则集
let mut cursor = root_node.walk();
for child in root_node.children(&mut cursor) {
if child.kind() == "rule_set" {
println!("Found rule set:");
// 获取选择器
let selector = child.child_by_field_name("selectors").unwrap();
println!(" Selector: {}", selector.utf8_text(css_code.as_bytes()).unwrap());
// 获取声明块
let block = child.child_by_field_name("block").unwrap();
println!(" Declarations:");
// 遍历声明
let mut block_cursor = block.walk();
for declaration in block.children(&mut block_cursor) {
if declaration.kind() == "declaration" {
let property = declaration.child_by_field_name("property").unwrap();
let value = declaration.child_by_field_name("value").unwrap();
println!(
" {}: {}",
property.utf8_text(css_code.as_bytes()).unwrap(),
value.utf8_text(css_code.as_bytes()).unwrap()
);
}
}
}
}
}
功能说明
- 创建解析器:使用
tree_sitter::Parser
创建解析器实例 - 设置语言:通过
tree_sitter_css::language()
设置 CSS 语法 - 解析代码:调用
parse()
方法解析 CSS 字符串 - 遍历语法树:可以通过节点的方法遍历和查询语法树结构
- 获取节点内容:使用
utf8_text()
方法获取节点对应的源代码
输出示例
运行上述代码将输出类似以下内容:
(stylesheet (rule_set (selectors (tag_name)) (block (declaration (property_name) (plain_value (string_value))) (declaration (property_name) (color_value)) (declaration (property_name) (plain_value (integer_value)))) (rule_set (selectors (class_name)) (block (declaration (property_name) (plain_value (integer_value) (unit)) (declaration (property_name) (plain_value (integer_value)) (declaration (property_name) (plain_value (integer_value)))))
Found rule set:
Selector: body
Declarations:
font-family: Arial, sans-serif
color: #333
margin: 0
Found rule set:
Selector: .container
Declarations:
max-width: 1200px
margin: 0 auto
完整示例代码
use tree_sitter::{Parser, TreeCursor};
use tree_sitter_css::language;
fn main() {
// 初始化解析器
let mut parser = Parser::new();
parser.set_language(language()).expect("加载CSS语法失败");
// CSS示例代码
let css = r#"
/* 这是一个CSS注释 */
body {
background: #fff;
font-size: 16px;
}
#header {
height: 80px;
display: flex;
}
@media (max-width: 768px) {
body {
font-size: 14px;
}
}
"#;
// 解析CSS代码
let tree = parser.parse(css, None).unwrap();
let root = tree.root_node();
// 打印语法树结构
println!("语法树结构:\n{}\n", root.to_sexp());
// 遍历所有节点
println!("开始遍历CSS节点:");
traverse_nodes(&root, css, 0);
}
fn traverse_nodes(node: &tree_sitter::Node, source: &str, depth: usize) {
// 打印当前节点信息
let indent = " ".repeat(depth);
println!("{}{}: {}", indent, node.kind(), node.utf8_text(source.as_bytes()).unwrap().trim());
// 递归遍历子节点
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
traverse_nodes(&child, source, depth + 1);
}
}
示例输出
语法树结构:
(stylesheet (comment) (rule_set (selectors (tag_name)) (block (declaration (property_name) (color_value)) (declaration (property_name) (plain_value (integer_value) (unit)))) (rule_set (selectors (id_selector)) (block (declaration (property_name) (plain_value (integer_value) (unit)) (declaration (property_name) (plain_value))) (at_rule (at_keyword) (parenthesized_value (plain_value (dimension) (integer_value) (unit))) (block (rule_set (selectors (tag_name)) (block (declaration (property_name) (plain_value (integer_value) (unit)))))))
开始遍历CSS节点:
stylesheet:
comment: /* 这是一个CSS注释 */
rule_set:
selectors: body
block:
declaration:
property_name: background
color_value: #fff
declaration:
property_name: font-size
plain_value: 16px
rule_set:
selectors: #header
block:
declaration:
property_name: height
plain_value: 80px
declaration:
property_name: display
plain_value: flex
at_rule:
at_keyword: @media
parenthesized_value: (max-width: 768px)
block:
rule_set:
selectors: body
block:
declaration:
property_name: font-size
plain_value: 14px
1 回复
Rust语法分析库tree-sitter-css的使用指南
概述
tree-sitter-css是一个用于解析CSS的Tree-sitter绑定库,它提供了高效解析和操作CSS代码的能力。Tree-sitter是一个增量解析系统,能够快速解析源代码并生成详细的语法树。
主要特性
- 高性能CSS解析
- 增量解析能力
- 精确的语法错误定位
- 支持查询和遍历语法树
安装方法
在Cargo.toml中添加依赖:
[dependencies]
tree-sitter = "0.20"
tree-sitter-css = "0.19"
基本使用方法
1. 解析CSS代码
use tree_sitter::Parser;
use tree_sitter_css::language;
fn main() {
let mut parser = Parser::new();
parser.set_language(language()).expect("Error loading CSS grammar");
let css_code = r#"
body {
color: #333;
margin: 0;
}
"#;
let tree = parser.parse(css_code, None).unwrap();
println!("{:#?}", tree.root_node());
}
2. 遍历语法树
fn walk_tree(node: tree_sitter::Node, source: &str, depth: usize) {
let indent = " ".repeat(depth);
println!("{}{:?}", indent, node.kind());
if node.child_count() > 0 {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
walk_tree(child, source, depth + 1);
}
} else {
println!("{} Text: {:?}", indent, node.utf8_text(source.as_bytes()).unwrap());
}
}
3. 查询特定节点
use tree_sitter::Query;
fn find_selectors(css: &str) {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
let query = Query::new(
language(),
"(rule_set (selectors) @selector)"
).unwrap();
let mut cursor = tree_sitter::QueryCursor::new();
for match_ in cursor.matches(&query, tree.root_node(), css.as_bytes()) {
for capture in match_.captures {
let node = capture.node;
println!("Selector: {}", node.utf8_text(css.as_bytes()).unwrap());
}
}
}
高级用法
1. 增量解析
fn incremental_parsing() {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let old_source = "body { color: red; }";
let tree = parser.parse(old_source, None).unwrap();
// 修改后的代码
let new_source = "body { color: blue; }";
// 增量解析
let new_tree = parser.parse(new_source, Some(&tree)).unwrap();
println!("New tree: {:?}", new_tree.root_node());
}
2. 语法高亮
use tree_sitter_highlight::{HighlightConfiguration, Highlighter, HighlightEvent};
fn highlight_css(css: &str) {
let mut highlighter = Highlighter::new();
let config = HighlightConfiguration::new(
language(),
"css",
tree_sitter_css::HIGHLIGHTS_QUERY,
"",
""
).unwrap();
let highlights = highlighter.highlight(
&config,
css.as_bytes(),
None,
|_| None
).unwrap();
for event in highlights {
match event.unwrap() {
HighlightEvent::Source {start, end} => {
println!("Text: {}", &css[start..end]);
}
HighlightEvent::HighlightStart(s) => {
println!("Highlight start: {:?}", s);
}
HighlightEvent::HighlightEnd => {
println!("Highlight end");
}
}
}
}
错误处理
fn parse_with_errors(css: &str) {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
if tree.root_node().has_error() {
let mut cursor = tree.walk();
for node in tree.root_node().children(&mut cursor) {
if node.is_error() {
println!("Error at {}:{}", node.start_position().row, node.start_position().column);
}
}
}
}
实际应用示例
提取所有CSS属性
fn extract_properties(css: &str) -> Vec<String> {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
let query = Query::new(
language(),
"(declaration (property_name) @property)"
).unwrap();
let mut properties = Vec::new();
let mut cursor = tree_sitter::QueryCursor::new();
for match_ in cursor.matches(&query, tree.root_node(), css.as_bytes()) {
for capture in match_.captures {
let node = capture.node;
properties.push(node.utf8_text(css.as_bytes()).unwrap().to_string());
}
}
properties
}
性能提示
- 重用Parser实例以减少初始化开销
- 对于大型CSS文件,使用增量解析
- 缓存常用查询以提高性能
tree-sitter-css为Rust开发者提供了强大的CSS解析能力,适用于构建CSS处理工具、编辑器插件、静态分析工具等各种应用场景。
完整示例代码
下面是一个结合了多个功能的完整示例:
use tree_sitter::{Parser, Query, QueryCursor};
use tree_sitter_css::language;
use tree_sitter_highlight::{HighlightConfiguration, Highlighter, HighlightEvent};
fn main() {
// 示例CSS代码
let css_code = r#"
body {
color: #333;
margin: 0;
font-family: Arial, sans-serif;
}
.container {
width: 100%;
padding: 20px;
}
/* 这是一个注释 */
#header {
background-color: #f0f0f0;
}
"#;
// 1. 初始化解析器
let mut parser = Parser::new();
parser.set_language(language()).expect("加载CSS语法失败");
// 2. 解析CSS代码
let tree = parser.parse(css_code, None).unwrap();
println!("语法树根节点: {:#?}", tree.root_node());
// 3. 遍历语法树
println!("\n遍历语法树:");
walk_tree(tree.root_node(), css_code, 0);
// 4. 查询选择器
println!("\n查询选择器:");
find_selectors(css_code);
// 5. 提取属性
println!("\n提取所有属性:");
let properties = extract_properties(css_code);
for prop in properties {
println!("- {}", prop);
}
// 6. 语法高亮
println!("\n语法高亮结果:");
highlight_css(css_code);
// 7. 错误处理演示
println!("\n错误处理演示:");
let invalid_css = "body { color: ; }";
parse_with_errors(invalid_css);
}
// 遍历语法树的函数
fn walk_tree(node: tree_sitter::Node, source: &str, depth: usize) {
let indent = " ".repeat(depth);
println!("{}{:?}", indent, node.kind());
if node.child_count() > 0 {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
walk_tree(child, source, depth + 1);
}
} else {
println!("{} Text: {:?}", indent, node.utf8_text(source.as_bytes()).unwrap());
}
}
// 查询选择器的函数
fn find_selectors(css: &str) {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
let query = Query::new(
language(),
"(rule_set (selectors) @selector"
).unwrap();
let mut cursor = QueryCursor::new();
for match_ in cursor.matches(&query, tree.root_node(), css.as_bytes()) {
for capture in match_.captures {
let node = capture.node;
println!("选择器: {}", node.utf8_text(css.as_bytes()).unwrap());
}
}
}
// 提取属性的函数
fn extract_properties(css: &str) -> Vec<String> {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
let query = Query::new(
language(),
"(declaration (property_name) @property)"
).unwrap();
let mut properties = Vec::new();
let mut cursor = QueryCursor::new();
for match_ in cursor.matches(&query, tree.root_node(), css.as_bytes()) {
for capture in match_.captures {
let node = capture.node;
properties.push(node.utf8_text(css.as_bytes()).unwrap().to_string());
}
}
properties
}
// 语法高亮的函数
fn highlight_css(css: &str) {
let mut highlighter = Highlighter::new();
let config = HighlightConfiguration::new(
language(),
"css",
tree_sitter_css::HIGHLIGHTS_QUERY,
"",
""
).unwrap();
let highlights = highlighter.highlight(
&config,
css.as_bytes(),
None,
|_| None
).unwrap();
for event in highlights {
match event.unwrap() {
HighlightEvent::Source {start, end} => {
println!("文本: {}", &css[start..end]);
}
HighlightEvent::HighlightStart(s) => {
println!("高亮开始: {:?}", s);
}
HighlightEvent::HighlightEnd => {
println!("高亮结束");
}
}
}
}
// 错误处理的函数
fn parse_with_errors(css: &str) {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(css, None).unwrap();
if tree.root_node().has_error() {
let mut cursor = tree.walk();
for node in tree.root_node().children(&mut cursor) {
if node.is_error() {
println!("错误位置: {}行{}列",
node.start_position().row + 1,
node.start_position().column + 1);
}
}
}
}
这个完整示例演示了如何使用tree-sitter-css库进行CSS代码的解析、遍历、查询、属性提取、语法高亮和错误处理。你可以根据需要选择使用其中的部分功能或全部功能。