Rust JSON查询解析库jaq-parse的使用,高效解析与处理JSON数据的强大工具

jaq(发音类似“Jacques”)是JSON数据处理工具jq的克隆。jaq旨在支持jq语法和操作的大部分子集。

您可以在jaq在线游乐场中尝试jaq。

jaq专注于三个目标:

  • 正确性:jaq旨在提供更正确和可预测的jq实现,同时在大多数情况下保持与jq的兼容性。
  • 性能:我最初创建jaq是因为我对jq的长启动时间感到困扰,这在我的机器上大约需要50毫秒。这在处理大量小文件时尤其明显。jaq的启动速度比jq 1.6快约30倍,并且在许多其他基准测试中也优于jq。
  • 简洁性:jaq旨在实现简单和小巧,以减少潜在的错误并促进贡献。

我从另一个Rust程序jql中获得了灵感。然而,与jql不同,jaq旨在紧密模仿jq的语法和语义。这应该使熟练使用jq的用户能够轻松使用jaq。

安装

二进制文件

您可以在发布页面下载适用于Linux、Mac和Windows的二进制文件。

您也可以使用homebrew在macOS或Linux上安装jaq:

$ brew install jaq
$ brew install --HEAD jaq # 最新开发版本

或在Windows上使用scoop安装:

$ scoop install main/jaq

从源代码编译

要编译jaq,您需要Rust工具链。(请注意,Linux发行版附带的Rust编译器可能太旧,无法编译jaq。)

以下任何命令都可以安装jaq:

$ cargo install --locked jaq
$ cargo install --locked --git https://github.com/01mf02/jaq # 最新开发版本

在我的系统上,这两个命令都将可执行文件放置在~/.cargo/bin/jaq

如果您已经克隆了此存储库,您也可以在克隆的存储库中执行以下命令之一来构建jaq:

$ cargo build --release # 将二进制文件放入target/release/jaq
$ cargo install --locked --path jaq # 安装二进制文件

jaq应该在任何Rust支持的系统上工作。如果不工作,请提交问题。

示例

以下示例应该让您了解jaq目前可以做什么。您应该通过将jaq替换为jq获得相同的输出。如果没有,您提交问题将不胜感激。 语法在jq手册中有文档记录。

访问字段:

$ echo '{"a": 1, "b": 2}' | jaq '.a'
1

添加值:

$ echo '{"a": 1, "b": 2}' | jaq 'add'
3

以两种方式从对象构造数组并显示它们相等:

$ echo '{"a": 1, "b": 2}' | jaq '[.a, .b] == [.[]]'
true

对数组的所有元素应用过滤器并过滤结果:

$ echo '[0, 1, 2, 3]' | jaq 'map(.*2) | [.[] | select(. < 5)]'
[0, 2, 4]

将(读取)输入值读入数组并获取其元素的平均值:

$ echo '1 2 3 4' | jaq -s 'add / length'
2.5

重复将过滤器应用于自身并输出中间结果:

$ echo '0' | jaq '[recurse(.+1; . < 3)]'
[0, 1, 2]

懒洋洋地对输入进行折叠并输出中间结果:

$ seq 1000 | jaq -n 'foreach inputs as $x (0; . + $x)'
1 3 6 10 15 [...]

完整示例代码

以下是一个完整的Rust示例,展示如何使用jaq-parse库来解析和处理JSON数据:

use jaq_parse::{parse, Def};
use serde_json::json;

fn main() {
    // 定义要处理的JSON数据
    let data = json!({
        "name": "Alice",
        "age": 30,
        "hobbies": ["reading", "hiking", "coding"]
    });

    // 定义jaq查询字符串
    let query = ".name, .age, .hobbies[]";

    // 解析查询
    let (main, defs) = parse(query, jaq_parse::main()).unwrap();
    
    // 输出解析结果
    println!("Parsed main: {:?}", main);
    println!("Parsed defs: {:?}", defs);
    
    // 注意:这里只是解析示例,实际执行查询需要jaq-interpret库
    // 完整处理需要结合jaq-interpret来执行查询
}

注释:

  • 首先导入必要的库
  • 创建示例JSON数据
  • 定义jaq查询字符串
  • 使用jaq_parse::parse解析查询
  • 输出解析结果
  • 注意:实际执行查询需要jaq-interpret库

这个示例展示了如何解析jaq查询,要完整执行查询还需要使用jaq-interpret库来处理JSON数据。

基于上述内容,以下是一个完整的jaq使用示例:

use jaq_interpret::{Ctx, FilterT, RcIter, Val};
use jaq_parse::{parse, Def};
use serde_json::json;
use std::io::{self, BufRead};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建示例JSON数据
    let data = json!({
        "users": [
            {
                "name": "Alice",
                "age": 30,
                "active": true,
                "scores": [85, 92, 78]
            },
            {
                "name": "Bob", 
                "age": 25,
                "active": false,
                "scores": [67, 89, 91]
            },
            {
                "name": "Charlie",
                "age": 35,
                "active": true,
                "scores": [95, 88, 76]
            }
        ]
    });

    // 将JSON数据转换为jaq可处理的Val类型
    let input = Val::from(data);

    // 定义jaq查询 - 获取所有活跃用户的名字和平均分
    let query = r#"
        .users[] 
        | select(.active == true) 
        | {name: .name, avg_score: (.scores | add / length)}
    "#;

    // 解析查询
    let (main, defs) = parse(query, jaq_parse::main()).unwrap();
    
    println!("解析的查询: {:?}", main);
    println!("解析的定义: {:?}", defs);

    // 创建执行上下文
    let ctx = Ctx::new(Vec::new(), &defs);
    
    // 创建输入迭代器
    let inputs = RcIter::new(core::iter::empty());
    
    // 执行查询
    let mut results = main.run((ctx, inputs), input);
    
    println!("\n查询结果:");
    // 输出所有结果
    while let Some(result) = results.next() {
        match result {
            Ok(val) => println!("{}", val),
            Err(e) => eprintln!("错误: {}", e),
        }
    }

    Ok(())
}
# Cargo.toml 依赖配置
[package]
name = "jaq-example"
version = "0.1.0"
edition = "2021"

[dependencies]
jaq-interpret = "0.9"    # jaq解释器库
jaq-parse = "0.9"        # jaq解析器库  
serde_json = "1.0"       # JSON处理库

注释说明:

  • 首先导入必要的jaq库和JSON处理库
  • 创建包含用户数据的复杂JSON对象
  • 定义jaq查询字符串,使用管道操作符和选择器
  • 使用jaq_parse解析查询语法
  • 将JSON数据转换为jaq可处理的Val类型
  • 创建执行上下文和输入迭代器
  • 执行查询并处理结果
  • 输出解析后的查询结构和执行结果

这个完整示例展示了jaq的核心功能,包括查询解析、数据转换和查询执行的全过程。


1 回复

jaq-parse:Rust中的高效JSON查询解析库

概述

jaq-parse是一个专为Rust设计的JSON查询解析库,它实现了jq查询语言的解析功能。该库专注于高效解析和处理JSON数据,提供了强大的查询能力,同时保持轻量级和高性能的特点。

主要特性

  • 完整的jq查询语言支持
  • 零拷贝解析
  • 高度优化的解析性能
  • 与serde_json无缝集成
  • 支持流式处理

安装方法

在Cargo.toml中添加依赖:

[dependencies]
jaq-parse = "0.2"
serde_json = "1.0"

基本使用方法

1. 解析简单查询

use jaq_parse::{parse, Filter};
use serde_json::Value;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let query = ".name";
    let filters = parse::parse(&query, parse::main())?;
    
    let json_data = r#"{"name": "Alice", "age": 30}"#;
    let value: Value = serde_json::from_str(json_data)?;
    
    // 应用查询
    for filter in filters {
        let result = filter.run(&value);
        println!("Result: {:?}", result);
    }
    
    Ok(())
}

2. 复杂查询示例

use jaq_parse::{parse, Filter};
use serde_json::Value;

fn complex_query() -> Result<(), Box<dyn std::error::Error>> {
    let query = ".users[] | select(.age > 18) | {name: .name, adult: true}";
    let filters = parse::parse(&query, parse::main())?;
    
    let json_data = r#"{
        "users": [
            {"name": "Alice", "age": 25},
            {"name": "Bob", "age": 17},
            {"name": "Charlie", "age": 32}
        ]
    }"#;
    
    let value: Value = serde_json::from_str(json_data)?;
    
    for filter in filters {
        let results = filter.run(&value);
        for result in results {
            println!("匹配结果: {}", result);
        }
    }
    
    Ok(())
}

3. 错误处理示例

use jaq_parse::{parse, Error};

fn handle_errors() {
    let invalid_query = "invalid.[]query";
    
    match parse::parse(&invalid_query, parse::main()) {
        Ok(filters) => {
            println!("解析成功: {:?}", filters);
        }
        Err(Error::Parse(err)) => {
            println!("解析错误: {}", err);
        }
        Err(e) => {
            println!("其他错误: {:?}", e);
        }
    }
}

高级功能

自定义函数扩展

use jaq_parse::{parse, Filter, Val};
use serde_json::Value;

fn custom_function_example() -> Result<(), Box<dyn std::error::Error>> {
    let query = "map(. * 2)";
    let mut filters = parse::parse(&query, parse::main())?;
    
    // 可以在这里添加自定义函数逻辑
    for filter in &mut filters {
        // 自定义处理逻辑
    }
    
    Ok(())
}

批量处理多个查询

use jaq_parse::parse;

fn batch_processing() -> Result<(), Box<dyn std::error::Error>> {
    let queries = vec![
        ".items[].name",
        ".items[] | select(.price > 100)",
        ".metadata.timestamp"
    ];
    
    for query in queries {
        let filters = parse::parse(&query, parse::main())?;
        println!("解析查询 '{}' 成功", query);
        // 处理每个查询...
    }
    
    Ok(())
}

完整示例demo

// 完整示例:使用jaq-parse进行JSON数据查询处理
use jaq_parse::{parse, Filter, Error};
use serde_json::{Value, json};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 示例JSON数据
    let json_data = r#"{
        "users": [
            {
                "id": 1,
                "name": "Alice",
                "age": 25,
                "email": "alice@example.com",
                "active": true,
                "roles": ["admin", "user"],
                "metadata": {
                    "created_at": "2023-01-15",
                    "last_login": "2023-10-20"
                }
            },
            {
                "id": 2,
                "name": "Bob",
                "age": 17,
                "email": "bob@example.com",
                "active": false,
                "roles": ["user"],
                "metadata": {
                    "created_at": "2023-03-10",
                    "last_login": "2023-09-05"
                }
            },
            {
                "id": 3,
                "name": "Charlie",
                "age": 32,
                "email": "charlie@example.com",
                "active": true,
                "roles": ["moderator", "user"],
                "metadata": {
                    "created_at": "2023-02-28",
                    "last_login": "2023-10-25"
                }
            }
        ],
        "total_count": 3,
        "timestamp": "2023-10-30T10:30:00Z"
    }"#;

    // 解析JSON数据
    let value: Value = serde_json::from_str(json_data)?;
    
    println!("=== 简单查询示例 ===");
    simple_query_example(&value)?;
    
    println!("\n=== 复杂查询示例 ===");
    complex_query_example(&value)?;
    
    println!("\n=== 批量查询示例 ===");
    batch_query_example(&value)?;
    
    println!("\n=== 错误处理示例 ===");
    error_handling_example();
    
    Ok(())
}

// 简单查询示例
fn simple_query_example(data: &Value) -> Result<(), Box<dyn std::error::Error>> {
    // 查询1:获取所有用户名
    let query1 = ".users[].name";
    let filters1 = parse::parse(query1, parse::main())?;
    
    println!("查询 '{}' 结果:", query1);
    for filter in filters1 {
        let results = filter.run(data);
        for result in results {
            println!("  - {}", result);
        }
    }
    
    // 查询2:获取总用户数
    let query2 = ".total_count";
    let filters2 = parse::parse(query2, parse::main())?;
    
    println!("查询 '{}' 结果:", query2);
    for filter in filters2 {
        let results = filter.run(data);
        for result in results {
            println!("  - {}", result);
        }
    }
    
    Ok(())
}

// 复杂查询示例
fn complex_query_example(data: &Value) -> Result<(), Box<dyn std::error::Error>> {
    // 查询活跃的成年用户信息
    let query = ".users[] | select(.age > 18 and .active == true) | {name: .name, age: .age, email: .email, roles: .roles}";
    let filters = parse::parse(query, parse::main())?;
    
    println!("查询活跃的成年用户:");
    for filter in filters {
        let results = filter.run(data);
        for result in results {
            println!("  - {}", result);
        }
    }
    
    // 查询用户角色统计
    let role_query = ".users[].roles[] | group_by(.) | map({role: .[0], count: length})";
    let role_filters = parse::parse(role_query, parse::main())?;
    
    println!("用户角色统计:");
    for filter in role_filters {
        let results = filter.run(data);
        for result in results {
            println!("  - {}", result);
        }
    }
    
    Ok(())
}

// 批量查询示例
fn batch_query_example(data: &Value) -> Result<(), Box<dyn std::error::Error>> {
    let queries = vec![
        ".users[0]", // 第一个用户
        ".users[-1]", // 最后一个用户
        ".users | length", // 用户数量
        ".timestamp", // 时间戳
    ];
    
    for query in queries {
        match parse::parse(query, parse::main()) {
            Ok(filters) => {
                println!("查询 '{}':", query);
                for filter in filters {
                    let results = filter.run(data);
                    for result in results {
                        println!("  - {}", result);
                    }
                }
            }
            Err(e) => {
                println!("查询 '{}' 解析失败: {:?}", query, e);
            }
        }
    }
    
    Ok(())
}

// 错误处理示例
fn error_handling_example() {
    let invalid_queries = vec![
        "invalid.[]query",
        ".users[invalid]",
        "select(.age >",
    ];
    
    for query in invalid_queries {
        match parse::parse(query, parse::main()) {
            Ok(filters) => {
                println!("查询 '{}' 解析成功", query);
            }
            Err(Error::Parse(err)) => {
                println!("查询 '{}' 解析错误: {}", query, err);
            }
            Err(e) => {
                println!("查询 '{}' 其他错误: {:?}", query, e);
            }
        }
    }
}

// 性能优化示例:重用解析结果
fn performance_optimization_example() -> Result<(), Box<dyn std::error::Error>> {
    // 需要重复使用的查询
    let user_query = ".users[] | select(.active == true) | {name: .name, email: .email}";
    
    // 解析一次并缓存
    let filters = parse::parse(user_query, parse::main())?;
    
    // 模拟多个JSON数据源
    let data_sources = vec![
        // 这里可以添加多个JSON数据
    ];
    
    for data in data_sources {
        for filter in &filters {
            let results = filter.run(&data);
            // 处理结果...
        }
    }
    
    Ok(())
}

性能优化建议

  1. 重用解析结果:对于重复使用的查询,解析一次后缓存Filter对象
  2. 使用零拷贝:利用jaq-parse的零拷贝特性处理大型JSON数据
  3. 批量处理:对多个数据项应用相同的查询时使用批量处理

注意事项

  • 确保输入的JSON数据格式正确
  • 复杂的查询可能会影响性能,建议进行性能测试
  • 错误处理是必须的,特别是处理用户输入的查询时

这个库为Rust开发者提供了强大的JSON查询能力,特别适合需要高效处理大量JSON数据的应用场景。

回到顶部