json_read/lib.rs
1//! Json 数据读取
2//! ```rust
3//! use json_read::JsonWrapper;
4//!
5//! #[test]
6//! fn test_config_util() {
7//! // 读取配置文件
8//! let wrapper = JsonWrapper::new("docs/config.json").unwrap();
9//! // 直接将json字符串转换成JsonWrapper
10//! // let warpper = JsonWrapper::from_string("......").unwrap();
11//!
12//! // 不管是对象,还是数组,都是直接通过`.`操作。address是对象,children是数组,name是children中对象的一个属性
13//! let x = wrapper.get("address.children.name");
14//! println!("address.children.name = {:?}", x);
15//!
16//! // get方法是获取数组,而get_one获取的是第一个元素
17//! let x = wrapper.get_one("address.x.y").as_str().unwrap();
18//! println!("address.x.y = {}", x);
19//! }
20//! ```
21use serde_json::Value;
22use std::io;
23use std::path::Path;
24use std::fs::File;
25use std::io::Read;
26
27#[derive(Debug)]
28pub struct JsonWrapper {
29 pub raw_data: String,
30 pub data: Value,
31}
32
33pub struct ValueWrapper<'a> {
34 value: &'a Value,
35}
36
37impl<'a> ValueWrapper<'a> {
38 /// 创建一个新的实例
39 ///
40 /// # 参数
41 /// * `value` - 指向Value的引用
42 ///
43 /// # 返回值
44 /// 返回包含指定value的新实例
45 pub fn new(value: &'a Value) -> Self {
46 Self { value }
47 }
48
49 /// 根据键名获取对应的值
50 ///
51 /// 该函数支持通过点号分隔的多层键名来访问嵌套的数据结构,
52 /// 也支持在数组中查找指定键名的值。
53 ///
54 /// # 参数
55 /// * `key` - 要查找的键名,可以是单层键名或点号分隔的多层键名
56 ///
57 /// # 返回值
58 /// 返回包含查找到的值的向量,如果未找到则包含Null值
59 pub fn get(&self, key: &'a str) -> Vec<&'a Value> {
60 let mut results = Vec::new();
61 if let Some((left, right)) = key.split_once(".") {
62 // 处理多层键名的情况
63 let x = self.value.get(left);
64 if x.is_none() {
65 results.push(&Value::Null);
66 } else {
67 let x = x.unwrap();
68 let next = ValueWrapper::new(x);
69 results.append(&mut next.get(right));
70 }
71 } else {
72 // 处理单层键名的情况
73 match self.value {
74 Value::Object(map) => {
75 // 在对象中查找键名
76 if let Some(v) = map.get(key) {
77 results.push(v);
78 } else {
79 results.push(&Value::Null);
80 }
81 }
82 Value::Array(vec) => {
83 // 在数组的每个元素中查找键名
84 for item in vec {
85 match item.get(key) {
86 Some(v) => results.push(v),
87 None => results.push(&Value::Null),
88 }
89 }
90 }
91 _ => results.push(&Value::Null),
92 }
93 }
94 results
95 }
96}
97
98impl JsonWrapper {
99 /// 创建一个新的配置实例
100 ///
101 /// 该函数会读取指定路径的配置文件,解析JSON格式的内容,并创建配置对象
102 ///
103 /// # 参数
104 /// * `file_path` - 配置文件的路径字符串引用
105 ///
106 /// # 返回值
107 /// 返回Result类型,成功时包含配置实例,失败时包含IO错误
108 ///
109 /// # 错误
110 /// 当文件读取失败或JSON解析失败时会返回相应的错误
111 pub fn new(file_path: &str) -> Result<Self, Box<dyn std::error::Error>> {
112 // 读取配置文件内容
113 let mut file = File::open(file_path)?;
114 let mut conf_string = String::new();
115 file.read_to_string(&mut conf_string)?;
116 // 解析JSON数据
117 let data: Value = serde_json::from_str(&conf_string)?;
118 Ok(Self {
119 raw_data: conf_string,
120 data,
121 })
122 }
123
124 pub fn from_string(conf_string: &str) -> io::Result<Self> {
125 let data: Value = serde_json::from_str(conf_string)?;
126 Ok(Self {
127 raw_data: conf_string.to_string(),
128 data,
129 })
130 }
131
132 /// 获取指定键对应的值列表
133 ///
134 /// 该函数通过创建一个值包装器来访问内部数据,并返回与给定键关联的所有值。
135 ///
136 /// # 参数
137 /// * `key` - 要查找的静态字符串键
138 ///
139 /// # 返回值
140 /// 返回一个包含所有匹配值的引用向量
141 pub fn get<'a, 'b: 'a>(&'a self, key: &'b str) -> Vec<&'a Value> {
142 let wrapper = ValueWrapper::new(&self.data);
143 wrapper.get(key)
144 }
145
146 /// 获取指定键对应的第一个值
147 ///
148 /// # 参数
149 /// * `key` - 要查找的键名,必须是静态字符串
150 ///
151 /// # 返回值
152 /// 返回键对应值的引用
153 ///
154 /// # 注意
155 /// 如果键不存在或对应的值为空,会触发panic
156 pub fn get_one<'a, 'b: 'a>(&'a self, key: &'b str) -> &'a Value {
157 // 该方法注释,要求b的生命周期不小于a的生命周期
158 // 创建值包装器来处理数据查询
159 let wrapper = ValueWrapper::new(&self.data);
160 // 获取指定键对应的值向量
161 let vec = wrapper.get(key);
162 // 返回向量中的第一个值,如果不存在则panic
163 vec.first().unwrap()
164 }
165}
166
167#[cfg(test)]
168mod tests {
169
170 use super::*;
171
172 #[test]
173 fn test_json_conf_util() {
174
175 let json_wrapper = JsonWrapper::new("docs/config.json").unwrap();
176
177 let x = json_wrapper.get("name");
178 // name = [String("Alice")]
179 println!("name = {:?}", x);
180
181 let x = json_wrapper.get("age");
182 // age = [Number(30)]
183 println!("age = {:?}", x);
184
185 let x = json_wrapper.get("is_student");
186 // is_student = [Bool(false)]
187 println!("is_student = {:?}", x);
188
189 let x = json_wrapper.get("hobbies");
190 // hobbies = [Array [String("reading"), String("swimming"), String("cooking")]]
191 println!("hobbies = {:?}", x);
192
193 let x = json_wrapper.get("address");
194 // address = [Object {"children": Array [Object {"age": Number(5), "name": String("r")}, Object {"age": Number(6), "name": String("s")}], "city": String("New York"), "releases": Array [String("v1"), String("v2")], "state": String("NY"), "street": String("123 Main St"), "x": Object {"y": String("hello, json!")}, "zip": String("10001")}]
195 println!("address = {:?}", x);
196
197 let x = json_wrapper.get("address.street");
198 // address.street = [String("123 Main St")]
199 println!("address.street = {:?}", x);
200
201 let x = json_wrapper.get("address.releases");
202 // address.releases = [Array [String("v1"), String("v2")]]
203 println!("address.releases = {:?}", x);
204
205 let x = json_wrapper.get("address.x.y");
206 // address.x.y = [String("hello, json!")]
207 println!("address.x.y = {:?}", x);
208
209 let x = json_wrapper.get("address.children.name");
210 // address.children.name = [String("r"), String("s")]
211 println!("address.children.name = {:?}", x);
212 println!("=============================================================");
213
214 let name = json_wrapper.get_one("name").as_str().unwrap();
215 let age = json_wrapper.get_one("age").as_i64().unwrap();
216 println!("name = {:?}", name);
217 println!("age = {:?}", age);
218
219 let key = String::from("address.x.y");
220 let x = json_wrapper.get_one(&key).as_str().unwrap();
221 // address.x.y = hello, json!
222 println!("address.x.y = {}", x);
223
224 }
225}