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>
相关推荐
用户4694651597831 小时前
Rust使用tracing记录日志
rust
编码浪子2 小时前
构建一个rust生产应用读书笔记7-确认邮件2
开发语言·后端·rust
轻口味3 小时前
【每日学点鸿蒙知识】私仓搭建、resources创建文件夹、hvigor如何动态设置版本、SM3摘要算法、SP存储报错等
华为·json·harmonyos
songroom9 小时前
Rust: offset祼指针操作
开发语言·算法·rust
唐 城16 小时前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
SEO-狼术17 小时前
Oxygen XML Developer Crack
xml
从善若水18 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
gerrylon00719 小时前
rust学习: 有用的命令
rust
alikami1 天前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
brrdg_sefg1 天前
Rust 在前端基建中的使用
前端·rust·状态模式