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>
相关推荐
光影6277 小时前
Unittest单元测试基础速记
测试工具·单元测试·json·测试覆盖率
ZLongTeng9 小时前
EIDE的launch.json文件
json
niyongsheng10 小时前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
Hello.Reader11 小时前
tsrs 技术解析用 Rust 移植 TypeScript 7,类型检查还能怎样提速?
开发语言·rust·typescript
王仔小奶13 小时前
Rust 正在接管金融圈?深度拆解一份高薪 FinTech 岗位 JD
开发语言·金融·rust
梦想不只是梦与想13 小时前
Python 中的 json 模块
python·json·对象转字符串
你为她披上外套时我正站在窗外15 小时前
subtitler v2.10 发布:3 个社区 PR、一个一天修掉的 issue,和关于 uuencode 的真相
rust
Thneonl15 小时前
熔断不是开关是状态机:Claude Code 路由内核的 3 条红线
人工智能·rust
Thneonl15 小时前
一个 Claude Code 本地代理,凭啥配了 3 个观测出口?
人工智能·rust
步行cgn16 小时前
JSON.stringify 详解:把 JavaScript 对象变成 JSON 字符串
开发语言·javascript·json