LoginSignup
7
1

More than 3 years have passed since last update.

【Rust】serdeでXMLへserializeする話

Last updated at Posted at 2020-12-09

はじめに

ハンズラボ Advent Calendar 2020 10日目を担当します@ryosukeeeeeです。

RustでJSONのserialize/deserializeするときはserdeserde_jsonを使うのが一般的です。少なくとも私の観測範囲では。
ある日、モックサーバをRust書いていたのですがXMLをserializeする必要に迫られました。
serde-xml-rsというcrateが見つかったのですが、ハマったところがあったので記事にしました。

サンプル1

Using derive · SerdeのコードをXML版に置き換えたコードを載せます。

コード

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename = "root")]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    let serialized = serde_xml_rs::to_string(&point).unwrap();
    println!("serialized = {}", serialized);

    let deserialized: Point = serde_xml_rs::from_str("<root><x>3</x><y>4</y></root>").unwrap();
    println!("deserialized = {:?}", deserialized);
}

実行結果

$ cargo run
serialized = <root><x>1</x><y>2</y></root>
deserialized = Point { x: 3, y: 4 }

ハマったところ

執筆時点での最新バージョン(0.4.0)ではVec型のserializeには対応していません。
試しに、サンプル2のようにVec型をもつ構造体Teamのserializeを実行してみました。

サンプル2

コード

use serde::Serialize;

#[derive(Serialize)]
#[serde(rename = "team")]
struct Team {
    people: Vec<Person>,
}

#[derive(Serialize)]
#[serde(rename = "person")]
struct Person {
    name: String,
}

impl Person {
    fn new(name: &str) -> Person {
        Person {
            name: name.to_string(),
        }
    }
}

fn main() {
    let team = Team {
        people: vec![Person::new("Joe"), Person::new("Jane")],
    };

    let serialized = serde_xml_rs::to_string(&team).unwrap();
    println!("serialized = {}", serialized);
}

実行結果

$ cargo run
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: UnsupportedOperation { operation: "serialize_seq" }', src/main.rs:28:53
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

unwrap()の処理でpanicしています。

serde-xml-rsのリポジトリをみてみると、Vec型へ対応したPRが複数提案されています。
ここではSupport seq and maps (refactor of #129) by adrianbenavides · Pull Request #142を使ってみましょう。

Cargo.tomlのdependenciesで↓のように指定します。

[dependencies]
serde-xml-rs =  { git = "https://github.com/adrianbenavides/serde-xml-rs.git", rev = "fc2d35e5e2d08c4e8c8dee13449ff3ce98de46c1" }

なお、deserializeには対応していないようです。

実行結果

$ cargo run
serialized = <team><people><person><name>Joe</name></person><person><name>Jane</name></person></people></team>

めでたくserialize出来ました🚀

最後に

ハンズラボ Advent Calendar 2020 明日の11日目は、 @fasahina さんです!お楽しみに🎉

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1