10 个版本 (4 个重大更改)

0.5.0 2023年4月7日
0.4.1 2023年2月25日
0.3.1 2023年2月20日
0.2.1 2023年2月12日
0.1.0 2023年1月31日

#773解析器实现

Download history 137/week @ 2024-07-29

每月137 次下载

自定义许可

225KB
4K SLoC

Crate docs.rs Build License

cborpath-rs

cborpath 是一个用 Rust 编写的 CBORPath 引擎。

CBORPath

CBORPath 是基于 CBOR 的 JSONPath 的适配,基于 JSONPath 互联网草案

语法摘要

路径

一个路径表达式是一个 CBOR 数组,当它应用于一个 CBOR 值(即参数)时,选择零个或多个参数的节点,并将这些节点作为节点列表输出。

一个路径始终以一个标识符开始

  • 一个根标识符($)用于绝对路径,
  • 一个当前节点标识符(@)用于相对路径。相对路径总是在过滤器上下文中使用。

然后是一个或多个

语法 描述
["$", <>] 由段组成的绝对路径
它始终以根标识符($)开始
["@", <>] 由段组成的相对路径
它始终以当前节点标识符(@)开始

将对输入值应用一个或多个选择器,并将结果连接成一个节点列表。

语法 描述
[<选择器>] 由一个或多个选择器组成的子段
<选择器> 子段的快捷方式,由一个独特的选择器组成
{"..": [<选择器>]} 后代段,由一个或多个选择器组成
{"..": <选择器>} 后代段的快捷方式,由一个独特的选择器组成

选择器

选择器产生一个包含零个或多个输入值的子节点的节点列表。

语法 描述
<CBOR文本>
<CBOR字节>
<CBOR整数>
<CBOR浮点数>
<CBOR布尔值>
<CBOR空值>
键选择器:根据子键选择 CBOR Map 的子节点
{"*": 1} 通配符选择器:选择一个节点的所有子节点
{"#": <索引> } 索引选择器:选择数组的索引子节点(从0开始)
{":": [<开始>, <结束>, <步长>]} 数组切片选择器:选择数组元素的一个子集
(在 开始结束 之间,步长为 步长
{"?": <布尔值-表达式>} 过滤器选择器:使用布尔表达式选择特定的子节点

布尔表达式

布尔表达式返回 truefalse,并由 过滤器选择器 用于过滤数组元素或映射项。

语法 描述
{"&&": [<布尔值-表达式>, <布尔值-表达式>]} 逻辑 AND
{"||": [<布尔值-表达式>, <布尔值-表达式>]} 逻辑 OR
{"!": <布尔值-表达式>} 逻辑 NOT
{"<=": [<可比较的>, <可比较的>]} 比较 `小于或等于`
{"<": [<可比较的>, <可比较的>]} 比较 小于
{"==": [<可比较的>, <可比较的>]} 比较 等于
{"!=": [<可比较的>, <可比较的>]} 比较 不等于
{">": [<可比较的>, <可比较的>]} 比较 大于
{">=": [<可比较的>, <可比较的>]} 比较 大于或等于
{"匹配": [<可比较的>, <正则表达式>]} 匹配函数,用于计算正则表达式的完全匹配。
返回布尔值
{"搜索": [<可比较的>, <正则表达式>]} 长度函数,用于计算正则表达式的子串匹配。
返回布尔值

可比较的

一个 可比较的 是一个 过滤器 比较的运算符或函数的参数。

语法 描述
<CBOR文本>
<CBOR字节>
<CBOR整数>
<CBOR浮点数>
<CBOR布尔值>
<CBOR空值>
一个 CBOR
["$", <单数->]
["@", <单数->]
一个单数路径(路径产生一个最多包含一个节点的节点列表)
{"长度": <可比较的>} 长度函数,用于计算值的长度。
返回一个无符号整数
{"计数": <路径>} 计数函数,用于计算路径中节点的数量。
返回一个无符号整数
{"": <路径>} 值函数,用于获取单个节点路径的数量。
返回一个 CBOR

单数段

一个 单数段 产生一个最多包含一个节点的节点列表。

语法 描述
<CBOR文本>
<CBOR字节>
<CBOR整数>
<CBOR浮点数>
<CBOR布尔值>
<CBOR空值>
键选择器:根据子键选择 CBOR Map 的子节点
{"#": <索引> } 索引选择器:选择数组的索引子节点(从0开始)

示例

本节为信息性内容。它提供了CBORPath表达式的示例。

这些示例基于表示书店(还有一辆自行车)的简单CBOR值。

{ "store": {
    "book": [
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 399
    }
  }
}

下表显示了可能应用于此示例的一些CBORPath查询及其预期结果。

语法 预期结果
["$", "store", "book", {"*": 1}, "author"] 书店中所有书的作者
["$", {"..": "author"}] 所有作者
["$", "store", {"*": 1}] 店中的所有东西,其中有一些书
还有一辆红色的自行车
["$", "store", {"..": "price"}] 店中所有物品的价格
["$", {"..": "book"}, {"#": 2}] 第三本书
["$", {"..": "book"}, {"#": -1}] 顺序中的最后一本书
["$", {"..": "book"}, [{"#": 0}, {"#": 1}]]
或者
["$", {"..": "book"}, {":": [0, 2, 1]}]
前两本书
["$", {"..": "book"}, {"?": ["@", "isbn"]}] 所有带有ISBN编号的书
["$", {"..": "book"}, {"?": {"<": [["@", "price"], 10.0]}}] 所有价格低于10的书
["$", {"..": {"*": 1}}] 所有映射项值和数组元素
包含在输入值中

库使用

以下是一些基于上一节示例的代码示例。

use cborpath::{CborPath, builder, Error};
use cbor_diag::parse_diag;

pub fn diag_to_bytes(cbor_diag_str: &str) -> Vec<u8> {
    parse_diag(cbor_diag_str).unwrap().to_bytes()
}

fn main() -> Result<(), Error> {
  let value = diag_to_bytes(
  r#"{ 
    "store": {
      "book": [
        { "category": "reference",
          "author": "Nigel Rees",
          "title": "Sayings of the Century",
          "price": 8.95
        },
        { "category": "fiction",
          "author": "Evelyn Waugh",
          "title": "Sword of Honour",
          "price": 12.99
        },
        { "category": "fiction",
          "author": "Herman Melville",
          "title": "Moby Dick",
          "isbn": "0-553-21311-3",
          "price": 8.99
        },
        { "category": "fiction",
          "author": "J. R. R. Tolkien",
          "title": "The Lord of the Rings",
          "isbn": "0-395-19395-8",
          "price": 22.99
        }
      ],
      "bicycle": {
        "color": "red",
        "price": 399
      }
    }
  }"#,
  );

  // the authors of all books in the store
  // ["$", "store", "book", {"*": 1}, "author"]
  let cbor_path = CborPath::builder()
      .key("store")
      .key("book")
      .wildcard()
      .key("author")
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
              "Nigel Rees",
              "Evelyn Waugh",
              "Herman Melville",
              "J. R. R. Tolkien"
          ]"#
      ),
      results
  );

  // all authors
  // ["$", {"..": "author"}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("author"))
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
              "Nigel Rees",
              "Evelyn Waugh",
              "Herman Melville",
              "J. R. R. Tolkien"
          ]"#
      ),
      results
  );

  // all things in store, which are some books and a red bicycle
  // ["$", "store", {"*": 1}]
  let cbor_path = CborPath::builder().key("store").wildcard().build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[[
                  { "category": "reference",
                      "author": "Nigel Rees",
                      "title": "Sayings of the Century",
                      "price": 8.95
                  },
                  { "category": "fiction",
                      "author": "Evelyn Waugh",
                      "title": "Sword of Honour",
                      "price": 12.99
                  },
                  { "category": "fiction",
                      "author": "Herman Melville",
                      "title": "Moby Dick",
                      "isbn": "0-553-21311-3",
                      "price": 8.99
                  },
                  { "category": "fiction",
                      "author": "J. R. R. Tolkien",
                      "title": "The Lord of the Rings",
                      "isbn": "0-395-19395-8",
                      "price": 22.99
                  }
              ],
              {
                  "color": "red",
                  "price": 399
              }]"#
      ),
      results
  );

  // the prices of everything in the store
  // ["$", "store", {"..": "price"}]
  let cbor_path = CborPath::builder()
      .key("store")
      .descendant(builder::segment().key("price"))
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
              399,
              8.95,
              12.99,
              8.99,
              22.99
          ]"#
      ),
      results
  );

  // the third book
  // ["$", {"..": "book"}, {"#": 2}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .index(2)
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[{
              "category": "fiction",
              "author": "Herman Melville",
              "title": "Moby Dick",
              "isbn": "0-553-21311-3",
              "price": 8.99
          }]"#
      ),
      results
  );

  // the last book in order
  // ["$", {"..": "book"}, {"#": -1}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .index(-1)
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[{
              "category": "fiction",
              "author": "J. R. R. Tolkien",
              "title": "The Lord of the Rings",
              "isbn": "0-395-19395-8",
              "price": 22.99
          }]"#
      ),
      results
  );

  // the first two books
  // ["$", {"..": "book"}, [{"#": 0}, {"#": 1}]]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .child(builder::segment().index(0).index(1))
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
          {
            "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          {
            "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          }]"#
      ),
      results
  );

  // the first two books
  // ["$", {"..": "book"}, {":": [0, 2, 1]}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .slice(0, 2, 1)
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
          {
            "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          {
            "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          }]"#
      ),
      results
  );

  // all books with an ISBN number
  // ["$", {"..": "book"}, {"?": ["@", "isbn"]}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .filter(builder::rel_path().key("isbn"))
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
          {
            "category": "fiction",
            "author": "Herman Melville",
            "title": "Moby Dick",
            "isbn": "0-553-21311-3",
            "price": 8.99
          },
          {
            "category": "fiction",
            "author": "J. R. R. Tolkien",
            "title": "The Lord of the Rings",
            "isbn": "0-395-19395-8",
            "price": 22.99
          }]"#
      ),
      results
  );

  // all books cheaper than 10
  // ["$", {"..": "book"}, {"?": {"<": [["@", "price"], 10.0]}}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().key("book"))
      .filter(builder::lt(
          builder::sing_rel_path().key("price"),
          builder::val(10.),
      ))
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[
          {
            "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          {
            "category": "fiction",
            "author": "Herman Melville",
            "title": "Moby Dick",
            "isbn": "0-553-21311-3",
            "price": 8.99
          }]"#
      ),
      results
  );

  // all map item values and array elements contained in input value
  // ["$", {"..": {"*": 1}}]
  let cbor_path = CborPath::builder()
      .descendant(builder::segment().wildcard())
      .build();
  let results = cbor_path.read_from_bytes(&value)?;
  assert_eq!(
      diag_to_bytes(
          r#"[{
            "book": [
              {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
              },
              {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
              },
              {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
              },
              {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
              }
            ],
            "bicycle": {
              "color": "red",
              "price": 399
            }
          },
          [
            {
              "category": "reference",
              "author": "Nigel Rees",
              "title": "Sayings of the Century",
              "price": 8.95
            },
            {
              "category": "fiction",
              "author": "Evelyn Waugh",
              "title": "Sword of Honour",
              "price": 12.99
            },
            {
              "category": "fiction",
              "author": "Herman Melville",
              "title": "Moby Dick",
              "isbn": "0-553-21311-3",
              "price": 8.99
            },
            {
              "category": "fiction",
              "author": "J. R. R. Tolkien",
              "title": "The Lord of the Rings",
              "isbn": "0-395-19395-8",
              "price": 22.99
            }
          ],
          {
            "color": "red",
            "price": 399
          },
          {
            "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          {
            "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          },
          {
            "category": "fiction",
            "author": "Herman Melville",
            "title": "Moby Dick",
            "isbn": "0-553-21311-3",
            "price": 8.99
          },
          {
            "category": "fiction",
            "author": "J. R. R. Tolkien",
            "title": "The Lord of the Rings",
            "isbn": "0-395-19395-8",
            "price": 22.99
          },
          "red",
          399,
          "reference",
          "Nigel Rees",
          "Sayings of the Century",
          8.95,
          "fiction",
          "Evelyn Waugh",
          "Sword of Honour",
          12.99,
          "fiction",
          "Herman Melville",
          "Moby Dick",
          "0-553-21311-3",
          8.99,
          "fiction",
          "J. R. R. Tolkien",
          "The Lord of the Rings",
          "0-395-19395-8",
          22.99
          ]"#
      ),
      results
  );

  Ok(())
}

依赖

~3–4MB
~72K SLoC