Rust 解析動態 JSON
JSON 可能是最常用的數據結構,可以將它用於配置、數據庫等。
json 數據結構的最佳實踐是爲每個屬性提供一個靜態 key,但有時我們需要處理動態 key。
serde_json
在 rust 中,我們使用的是 serde_json 庫,它有很好用的 api。讓我們看看如何用 serde_json 解析 json。
讓我們將 serde 依賴添加到 Cargo.toml 中。我們將使用 serde 將數據序列化爲 struct:
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
現在讓我們解析一些帶有靜態 key 屬性的 json:
use serde::{Deserialize, Serialize};
use serde_json::Result;
#[derive(Serialize, Deserialize)]
struct User {
username: String,
age: usize,
email: String,
full_name: Vec<String>,
}
pub fn main() -> Result<()> {
let data = r#"
{
"username": "ahmadrosid",
"email": "alahmadrosid@gmail.com",
"age": 27,
"full_name": [
"Ahmad",
"Rosid"
]
}"#;
let u: User = serde_json::from_str(data)?;
println!("Hi {}", u.full_name[0]);
Ok(())
}
使用靜態 key 屬性,我們可以很容易地向結構聲明鍵和類型。但如果 key 是動態的,我們就無法這麼處理。
動態 Json
幸運的是,serde_json 有個枚舉 Value 來處理 json 的數據結構:
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
有了這個 enum,我們可以檢查每個 key 並對其進行一些序列化。現在,假設我們有這個 json:
{
"plugins": {
"width": [["w",["width"]]],
"height": [["h",["height"]]],
"z_index": [["z",["z-index"]]]
}
}
這看起來很簡單,對吧?我們可以像這樣輕鬆地定義 struct:
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Plugin,
}
#[derive(Serialize, Deserialize)]
struct Plugin {
width: Vec<Value>,
height: Vec<Value>,
z_index: Vec<Value>,
}
但是,如果 plugins 內部的 key 是動態的,例如,如果 z_index 變成了 z-index,並且多於三個 key,該怎麼辦呢?
爲了處理這種情況,我們需要把這個數據轉換爲 Map<String, Value>。現在我們可以將 struct 寫成這樣:
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Map<String, Value>,
}
現在我們可以像這樣訪問數據:
let data: Data = serde_json::from_str(json)?;
let z_index: Value = data.get("z_index").unwrap();
要將 Value 轉換爲數組,我們可以這樣做:
let z_index_arr: Vec<&Value> = z_index.as_array().unwrap();
我們還可以通過將數組 z_index 中的值轉換爲鍵值來改進。正如你所看到的,z_index 的值是數組中的數組:
[
[
"z",
[
"z-index"
]
]
]
讓我們把這個值轉換爲:
{
"z": ["z-index"]
}
爲此,我們將直接使用 Map<String, Value>:
let z_index_arr = z_index.as_array().unwrap();
let mut data = Map::new();
for item in z_index_arr {
if item.get(0).unwrap().is_string() {
let key = item.get(0).unwrap().as_str().unwrap().to_string();
let variants = item.get(1).unwrap().clone();
data.insert(key, variants);
}
}
現在我們可以這樣訪問 z-index 的值:
let arr = data.get("z").unwrap();
println!("{}", arr);
完整代碼如下:
use serde::{Serialize, Deserialize};
use serde_json::{Result, Map, Value};
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Map<String, Value>
}
fn main() -> Result<()> {
let json = r#"
{
"plugins": {
"width": [["w",["width"]]],
"height": [["h",["height"]]],
"z_index": [["z",["z-index"]]]
}
}
"#;
let data: Data = serde_json::from_str(json)?;
let z_index = data.plugins.get("z_index").unwrap();
let z_index_arr = z_index.as_array().unwrap();
let mut data = Map::new();
for item in z_index_arr {
if item.get(0).unwrap().is_string() {
let key = item.get(0).unwrap().as_str().unwrap().to_string();
let variants = item.get(1).unwrap().clone();
data.insert(key, variants);
}
}
let arr = data.get("z").unwrap();
println!("{}", arr);
Ok(())
}
就這些了,可以查看 serde 的文檔瞭解更多使用方法。
本文翻譯自:
https://www.ahmadrosid.com/blog/rust-parsing-dynamic-json
coding 到燈火闌珊 專注於技術分享,包括 Rust、Golang、分佈式架構、雲原生等。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ehUa3Fn7zg_oUwuD03Ufyw