Rust 实战练习 - 10. JSON、XML、YAML/TOML、Ini专题

配置文件

常见的配置文件有很多:JSON, Ini, XML, TOML, YAML ...

目标:

  • JSON/YAML/TOML
  • Ini
  • XML

Rust中序列化用的最多的是 serde, 依赖它,有很多出色的第三方库可以使用。

其中,serde本身支持JSON/YAML/TOML/JSON5...多种,这里使用serde_json.

XML需要第三方库quick-xml,他通过支持serde也支持了结构体序列化,配合十分完美.

INI比较特别,这里有一个比较强大的库,支持带注释的ini, configparser.

依赖文件:

toml 复制代码
[dependencies]
configparser = "*"  # ini支持
serde = { version = "*", features = ["derive"] }  # 后续的库的基础
serde_json = "*"  # JSON支持
quick-xml = { version = "*",features=["serde","serialize"] } # xml 支持

Code

rust 复制代码
use configparser::ini::Ini;
use serde_json::{json, Value};
use serde::{Deserialize, Serialize};
use quick_xml;

fn main() {
    println!("\r\n1. Ini config");
    ini_call();

    println!("\r\n2. Json config");
    // serde库 支持 json, toml, yaml ... 多种格式,方法也类似
    json_call();

    println!("\r\n3. XML config");
    // 支持 xml encoding 设定
    xml_call();
}

fn ini_call() {
    let ini_str = r#"default_s1 = 123 ; default section
    config s2 : abc,xyz # : also can be accept
  
   # comments 
[ app ]
port # default value is also ok
  ip = "192.168.1.2" 
  "#;

    let mut conf = Ini::new();
    // 解析 ini 内容
    if let Ok(cfg) = conf.read(ini_str.to_string()) {
        for (k, v) in cfg {
            println!("ini section: {} = {:?}", k, v);
        }

        println!("{:?}, {:?}", conf.getint("default", "default_s1"), conf.get("app", "ip"));

        // 修改 ini
        conf.set("app", "test", Some("t_val".to_string()));
        
        // output ini
        println!("\r\nini output:\r\n{}", conf.writes());
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}


fn json_call() {
    let s1 = r#"
    {
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    }"#;

    // 解析 json
    // map 方式访问,支持数组
    if let Ok(mut v) = serde_json::from_str::<Value>(s1) {
        println!("{:?} {}", v.get("name"), v["phones"][0]);
        // 修改 Json
        v["test"]=serde_json::value::Value::String("xxxx".to_string());
        println!("value change: {}", v.to_string());
    }
    // 结构体映射
    if let Ok(mut p) = serde_json::from_str::<Person>(s1) {
        println!("{:?}", p);
        
        // 修改 Json
        p.phones.push("1008611".to_string());
        println!("after: {}", serde_json::to_string_pretty(&p).unwrap());

    }

    // macro json Value
    let v1 = json!({
        "name": "zhangsan",
        "age": 33,
        "phones": ["1", "2"]
    });
    
    println!("value macro: {}", v1.to_string());
}

#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default)]
struct Translation {
    #[serde(rename = "@Tag")]  // @属性
    tag: String,
    #[serde(rename = "@Language")]
    lang: String,
    #[serde(rename = "$text")]  // $内容
    text: String,
}

#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default)]
struct DefaultSettings {
    #[serde(rename = "@Language")]
    language: String,
    #[serde(rename = "@Greeting")]
    greeting: String,
}

#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(default, rename_all = "PascalCase")]
struct Config {
    #[serde(rename = "DefaultSettings")]
    settings: DefaultSettings,
    localization: Localization,
}
#[derive(Debug, PartialEq, Default, Serialize,Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Localization {
    translation: Vec<Translation>,
}

const XML: &str = r#"
<?xml version="1.0" encoding="utf-8"?>
<Config>
  <DefaultSettings Language="es" Greeting="HELLO"/>
  <Localization>
    <Translation Tag="HELLO" Language="ja">
      こんにちは
    </Translation>
    <Translation Tag="BYE" Language="ja">
      さようなら
    </Translation>
    <Translation Tag="HELLO" Language="es">
      Hola
    </Translation>
    <Translation Tag="BYE" Language="es">
      Adiós
    </Translation>
  </Localization>
</Config>
"#;

const XML2: &str = r#"
    <Translation Tag="HELLO" Language="ja">
      こんにちは
    </Translation>
"#;
fn xml_call(){
    // 简单解析XML
    if let Ok(t2) = quick_xml::de::from_str::<Translation>(XML2){
        println!("xml2 struct:\r\n\t {:?}", t2);
    }

    // 复杂的解析XML
    if let Ok(mut t) = quick_xml::de::from_str::<Config>(XML){
        println!("xml settings: \r\n\t{:?}", t.settings);
        println!("xml localization: \r\n\t{:?}", t.localization);

        // 修改XML
        t.settings.greeting = "good good study".to_string();

        // out
        println!("format output:\r\n\t{}",quick_xml::se::to_string(&t).unwrap());
    }
}

输出

js 复制代码
1. Ini config
ini section: app = {"ip": Some("\"192.168.1.2\""), "port": None}
ini section: default = {"default_s1": Some("123"), "config s2": Some("abc,xyz")}
Ok(Some(123)), Some("\"192.168.1.2\"")

ini output:
default_s1=123
config s2=abc,xyz
[app]
ip="192.168.1.2"
test=t_val
port


2. Json config
Some(String("John Doe")) "+44 1234567"
value change: {"age":43,"name":"John Doe","phones":["+44 1234567","+44 2345678"],"test":"xxxx"}
Person { name: "John Doe", age: 43, phones: ["+44 1234567", "+44 2345678"] }
after: {
  "name": "John Doe",
  "age": 43,
  "phones": [
    "+44 1234567",
    "+44 2345678",
    "1008611"
  ]
}
value macro: {"age":33,"name":"zhangsan","phones":["1","2"]}

3. XML config
xml2 struct:
         Translation { tag: "HELLO", lang: "ja", text: "こんにちは" }
xml settings: 
        DefaultSettings { language: "es", greeting: "HELLO" }
xml localization: 
        Localization { translation: [Translation { tag: "HELLO", lang: "ja", text: "こんにちは" }, Translation { tag: "BYE", lang: "ja", text: "さようなら" }, Translation { tag: "HELLO", lang: "es", text: "Hola" }, Translation { tag: "BYE", lang: "es", text: "Adiós" }] }
format output:
        <Config><DefaultSettings Language="es" Greeting="good good study"/><Localization><Translation Tag="HELLO" Language="ja">こんにちは</Translation><Translation Tag="BYE" Language="ja">さようなら</Translation><Translation Tag="HELLO" Language="es">Hola</Translation><Translation Tag="BYE" Language="es">Adiós</Translation></Localization></Config>
相关推荐
测试杂货铺7 小时前
Jmeter(六):json断言元件,jmeter参数化实现
jmeter·json
专注VB编程开发20年12 小时前
C#,VB.NET从JSON数据里提取数组中的对象节点值
c#·json·.net
Pomelo_刘金14 小时前
Rust 宣布发布1.88.0
rust
寻月隐君16 小时前
告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力
后端·rust·github
草履虫建模17 小时前
Postman - API 调试与开发工具 - 标准使用流程
java·测试工具·spring·json·测试用例·postman·集成学习
大卫小东(Sheldon)21 小时前
GIM 1.5发布了! 支持Windows系统了
git·ai·rust
寻月隐君1 天前
告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践
后端·rust·github
李少兄10 天前
解决OSS存储桶未创建导致的XML错误
xml·开发语言·python
成遇10 天前
在Vscode中安装Sass并配置
vscode·rust·sass
止观止10 天前
Rust智能指针演进:从堆分配到零复制的内存管理艺术
开发语言·后端·rust