Rust YAML解析库yaml_parser的使用,高效处理YAML格式数据的序列化与反序列化

Rust YAML解析库yaml_parser的使用,高效处理YAML格式数据的序列化与反序列化

yaml_parser是一个半容忍的YAML具体语法树(CST)解析器。

基本用法

match yaml_parser::parse(&code) {
    Ok(tree) => println!("{tree:#?}"),
    Err(err) => eprintln!("{err}"),
};

解析成功后会生成rowan树。要消费这个树,请参考rowan的文档。

如果需要从CST构建AST,可以使用ast模块:

let root = yaml_parser::ast::Root::cast(tree).unwrap();
dbg!(root);

完整示例

下面是一个完整的示例,展示如何使用yaml_parser进行YAML数据的序列化和反序列化:

use yaml_parser::ast::Root;

fn main() {
    // 示例YAML数据
    let yaml_data = r"
    name: John Doe
    age: 30
    address:
      street: 123 Main St
      city: Anytown
    hobbies:
      - reading
      - hiking
    ";

    // 解析YAML数据
    match yaml_parser::parse(yaml_data) {
        Ok(tree) => {
            println!("解析成功,完整的语法树:");
            println!("{tree:#?}");
            
            // 转换为AST
            if let Some(root) = Root::cast(tree) {
                println!("\n转换为抽象语法树(AST):");
                println!("{root:#?}");
                
                // 这里可以添加处理AST的逻辑
                // 例如访问特定的节点或值
            } else {
                eprintln!("无法将语法树转换为AST");
            }
        }
        Err(err) => {
            eprintln!("解析YAML时出错: {}", err);
        }
    }
}

完整示例demo

以下是更完整的示例,展示如何从YAML文件中读取数据并处理:

use yaml_parser::ast::{Root, Value};
use std::fs;

fn main() {
    // 从文件读取YAML数据
    let yaml_data = match fs::read_to_string("data.yaml") {
        Ok(content) => content,
        Err(err) => {
            eprintln!("读取文件失败: {}", err);
            return;
        }
    };

    // 解析YAML数据
    match yaml_parser::parse(&yaml_data) {
        Ok(tree) => {
            // 转换为AST
            if let Some(root) = Root::cast(tree) {
                // 访问特定节点
                if let Some(name) = root.value().and_then(|v| v.as_mapping())
                    .and_then(|m| m.get("name"))
                    .and_then(|v| v.as_str())
                {
                    println!("姓名: {}", name);
                }

                // 处理嵌套结构
                if let Some(address) = root.value().and_then(|v| v.as_mapping())
                    .and_then(|m| m.get("address"))
                    .and_then(|v| v.as_mapping())
                {
                    if let Some(street) = address.get("street").and_then(|v| v.as_str()) {
                        println!("街道: {}", street);
                    }
                }

                // 处理数组
                if let Some(hobbies) = root.value().and_then(|v| v.as_mapping())
                    .and_then(|m| m.get("hobbies"))
                    .and_then(|v| v.as_sequence())
                {
                    println!("兴趣爱好:");
                    for hobby in hobbies {
                        if let Value::String(hobby) = hobby {
                            println!("- {}", hobby.text());
                        }
                    }
                }
            }
        }
        Err(err) => {
            eprintln!("解析YAML时出错: {}", err);
        }
    }
}

测试

测试用例来源于官方的YAML测试套件。

许可证

MIT许可证

版权所有 © 2024-present Pig Fang


1 回复

Rust YAML解析库yaml_parser的使用

介绍

yaml_parser是Rust中一个高效的YAML格式数据解析库,专门用于YAML数据的序列化和反序列化操作。它提供了简单易用的API来处理YAML格式的数据,适合需要读取或生成YAML配置文件的场景。

主要特性

  • 轻量级且高效的YAML解析
  • 支持YAML 1.2规范
  • 提供序列化和反序列化功能
  • 良好的错误处理机制
  • 支持自定义类型转换

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
yaml_parser = "0.4"  # 请使用最新版本

基本解析示例

use yaml_parser::Yaml;

fn main() {
    let yaml_str = r#"
        name: John Doe
        age: 30
        is_active: true
        hobbies:
          - reading
          - hiking
          - coding
    "#;

    let yaml = Yaml::parse(yaml_str).expect("Failed to parse YAML");
    
    // 访问解析后的数据
    if let Some(name) = yaml["name"].as_str() {
        println!("Name: {}", name);
    }
    
    if let Some(age) = yaml["age"].as_i64() {
        println!("Age: {}", age);
    }
    
    if let Some(hobbies) = yaml["hobbies"].as_vec() {
        println!("Hobbies:");
        for hobby in hobbies {
            if let Some(h) = hobby.as_str() {
                println!("- {}", h);
            }
        }
    }
}

序列化示例

use yaml_parser::{Yaml, YamlEmitter};

fn main() {
    let mut yaml = Yaml::new_hash();
    
    yaml["name"] = "Jane Smith".into();
    yaml["age"] = 28.into();
    yaml["is_employee"] = true.into();
    
    let mut hobbies = Yaml::new_array();
    hobbies.push("swimming".into());
    hobbies.push("painting".into());
    yaml["hobbies"] = hobbies;
    
    // 将YAML对象序列化为字符串
    let mut output = String::new();
    let mut emitter = YamlEmitter::new(&mut output);
    emitter.dump(&yaml).expect("Failed to serialize YAML");
    
    println!("Generated YAML:\n{}", output);
}

自定义结构体解析

use yaml_parser::{Yaml, YamlLoader};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    age: u32,
    is_active: bool,
    hobbies: Vec<String>,
}

fn main() {
    let yaml_str = r#"
        name: Alice
        age: 25
        is_active: true
        hobbies:
          - photography
          - traveling
    "#;
    
    // 使用YamlLoader解析
    let docs = YamlLoader::load_from_str(yaml_str).unwrap();
    let doc = &docs[0];
    
    // 转换为自定义结构体
    let person: Person = serde_yaml::from_str(yaml_str).unwrap();
    println!("{:?}", person);
    
    // 从结构体生成YAML
    let yaml = serde_yaml::to_string(&person).unwrap();
    println!("Serialized YAML:\n{}", yaml);
}

高级用法

错误处理

use yaml_parser::{Yaml, YamlLoader};

fn parse_yaml_config(config: &str) -> Result<Yaml, String> {
    YamlLoader::load_from_str(config)
        .map_err(|e| format!("YAML parsing error: {}", e))
        .and_then(|docs| {
            if docs.is_empty() {
                Err("Empty YAML document".to_string())
            } else {
                Ok(docs[0].clone())
            }
        })
}

fn main() {
    let yaml_str = "invalid: yaml: here";
    
    match parse_yaml_config(yaml_str) {
        Ok(yaml) => println!("Parsed YAML: {:?}", yaml),
        Err(e) => println!("Error: {}", e),
    }
}

处理复杂结构

use yaml_parser::Yaml;

fn main() {
    let yaml_str = r#"
        users:
          - name: Bob
            roles: [admin, user]
            settings:
              theme: dark
              notifications: true
          - name: Eve
            roles: [user]
            settings:
              theme: light
              notifications: false
    "#;
    
    let yaml = Yaml::parse(yaml_str).unwrap();
    
    if let Some(users) = yaml["users"].as_vec() {
        for user in users {
            if let Some(name) = user["name"].as_str() {
                println!("User: {}", name);
                
                if let Some(roles) = user["roles"].as_vec() {
                    print!("Roles: ");
                    for role in roles {
                        if let Some(r) = role.as_str() {
                            print!("{} ", r);
                        }
                    }
                    println!();
                }
                
                if let Some(theme) = user["settings"]["theme"].as_str() {
                    println!("Theme: {}", theme);
                }
            }
        }
    }
}

性能提示

  1. 对于大型YAML文件,考虑使用流式解析
  2. 复用YamlParser实例来解析多个文档
  3. 避免频繁的字符串分配,尽量使用引用

yaml_parser库提供了灵活而强大的工具来处理YAML数据,无论是简单的配置文件还是复杂的数据结构,都能高效地完成序列化和反序列化任务。

完整示例demo

下面是一个结合了基本解析和序列化的完整示例:

use yaml_parser::{Yaml, YamlEmitter};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct Config {
    server: ServerConfig,
    database: DatabaseConfig,
    features: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ServerConfig {
    host: String,
    port: u16,
    ssl: bool,
}

#[derive(Debug, Serialize, Deserialize)]
struct DatabaseConfig {
    url: String,
    pool_size: u32,
    timeout: u32,
}

fn main() {
    // 示例YAML配置
    let yaml_str = r#"
        server:
          host: example.com
          port: 443
          ssl: true
        database:
          url: postgres://user:pass@localhost/db
          pool_size: 10
          timeout: 30
        features:
          - logging
          - metrics
          - caching
    "#;

    // 解析YAML为Config结构体
    let config: Config = serde_yaml::from_str(yaml_str).unwrap();
    println!("Parsed config: {:#?}", config);

    // 修改配置
    let mut config = config;
    config.server.port = 8080;
    config.features.push("compression".to_string());

    // 序列化回YAML
    let yaml_str = serde_yaml::to_string(&config).unwrap();
    println!("Modified YAML:\n{}", yaml_str);

    // 使用yaml_parser直接操作YAML
    let yaml = Yaml::parse(&yaml_str).unwrap();
    if let Some(features) = yaml["features"].as_vec() {
        println!("Features count: {}", features.len());
    }
}

这个完整示例展示了:

  1. 定义嵌套的结构体来表示配置
  2. 从YAML字符串反序列化为Rust结构体
  3. 修改结构体数据
  4. 将结构体序列化回YAML字符串
  5. 使用yaml_parser直接操作YAML数据
回到顶部