Rust XML序列化与反序列化库yaserde_derive的使用,高效实现Rust结构体与XML格式互转

Rust XML序列化与反序列化库yaserde_derive的使用,高效实现Rust结构体与XML格式互转

目标

该库支持XML的序列化和反序列化,并提供所有特定功能。

支持的类型

  • 结构体(Struct)
  • 向量(Vec)
  • 枚举(Enum)
  • 包含复杂类型的枚举(Enum with complex types)
  • 可选类型(Option)
  • 字符串(String)
  • 布尔值(bool)
  • 数字(u8, i8, u32, i32, f32, f64)

属性

  • attribute: 将字段定义为属性
  • default: 定义初始化字段的默认函数
  • flatten: 展平字段内容
  • namespace: 定义字段的命名空间
  • rename: 重命名字段
  • root: 重命名基础元素,仅用于XML根元素
  • skip_serializing: 从序列化输出中排除此字段
  • skip_serializing_if: 如果条件为真,则跳过此字段的序列化
  • text: 此字段匹配文本内容

自定义序列化/反序列化

任何类型都可以定义自定义的序列化器和/或反序列化器。要实现这一点,需要定义YaDeserialize/YaSerialize的实现。

impl YaDeserialize for MyType {
  fn deserialize<R: Read>(reader: &mut yaserde::de::Deserializer<R>) -> Result<Self, String> {
    // 反序列化代码
  }
}
impl YaSerialize for MyType {
  fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>) -> Result<(), String> {
    // 序列化代码
  }
}

完整示例

下面是一个完整的示例,展示如何使用yaserde_derive进行XML序列化和反序列化:

use yaserde_derive::{YaDeserialize, YaSerialize};

// 定义可序列化/反序列化的结构体
#[derive(Debug, YaSerialize, YaDeserialize)]
#[yaserde(
    root = "book",
    namespace = "ns: http://example.com"
)]
pub struct Book {
    #[yaserde(attribute)]
    id: String,
    
    #[yaserde(rename = "title")]
    name: String,
    
    #[yaserde(skip_serializing_if = "Option::is_none")]
    author: Option<String>,
    
    #[yaserde(rename = "price")]
    cost: f64,
    
    #[yaserde(text)]
    description: String,
}

fn main() {
    // 创建Book实例
    let book = Book {
        id: "123".to_string(),
        name: "Rust Programming".to_string(),
        author: Some("John Doe".to_string()),
        cost: 29.99,
        description: "A book about Rust programming".to_string(),
    };

    // 序列化为XML
    let xml = yaserde::ser::to_string(&book).unwrap();
    println!("Serialized XML:\n{}", xml);

    // 反序列化回结构体
    let deserialized_book: Book = yaserde::de::from_str(&xml).unwrap();
    println!("Deserialized struct:\n{:?}", deserialized_book);
}

这个示例展示了:

  1. 定义了一个带有各种yaserde属性的Book结构体
  2. 创建了一个Book实例
  3. 将其序列化为XML字符串
  4. 从XML字符串反序列化回Book结构体

输出结果将显示序列化后的XML和反序列化后的结构体内容。

完整示例代码

// 引入必要的库
use yaserde_derive::{YaDeserialize, YaSerialize};

// 定义一个表示用户的结构体
#[derive(Debug, PartialEq, YaSerialize, YaDeserialize)]
#[yaserde(
    root = "user",
    namespace = "example: http://example.org"
)]
struct User {
    #[yaserde(attribute, rename = "user_id")]
    id: u32,
    
    #[yaserde(rename = "full_name")]
    name: String,
    
    #[yaserde(skip_serializing_if = "Option::is_none")]
    email: Option<String>,
    
    #[yaserde(flatten)]
    address: Address,
    
    #[yaserde(rename = "active")]
    is_active: bool,
    
    #[yaserde(text)]
    bio: String,
}

// 定义地址结构体
#[derive(Debug, PartialEq, YaSerialize, YaDeserialize)]
struct Address {
    street: String,
    city: String,
    zip_code: String,
}

fn main() {
    // 创建User实例
    let user = User {
        id: 42,
        name: "Alice Smith".to_string(),
        email: Some("alice@example.com".to_string()),
        address: Address {
            street: "123 Main St".to_string(),
            city: "New York".to_string(),
            zip_code: "10001".to_string(),
        },
        is_active: true,
        bio: "Software developer with Rust experience".to_string(),
    };

    // 序列化为XML
    let xml_data = yaserde::ser::to_string(&user).unwrap();
    println!("序列化后的XML:\n{}", xml_data);

    // 反序列化回User结构体
    let deserialized_user: User = yaserde::de::from_str(&xml_data).unwrap();
    println!("\n反序列化后的结构体:\n{:#?}", deserialized_user);

    // 验证序列化和反序列化是否一致
    assert_eq!(user, deserialized_user);
    println!("\n验证通过:序列化和反序列化结果一致");
}

这个示例展示了:

  1. 定义了一个更复杂的User结构体,包含嵌套结构体Address
  2. 使用了多种yaserde属性(attribute, rename, skip_serializing_if, flatten, text等)
  3. 实现了完整的序列化和反序列化流程
  4. 包含了验证步骤确保数据一致性

输出结果将显示序列化后的XML格式和反序列化后的User结构体内容。


1 回复

Rust XML序列化与反序列化库yaserde_derive的使用

简介

yaserde_derive是一个Rust库,用于实现结构体与XML格式之间的序列化和反序列化。它通过过程宏提供了一种简单的方式来标注Rust结构体,使其能够与XML相互转换。

主要特性

  • 支持结构体与XML的相互转换
  • 提供自定义标签名、命名空间等配置选项
  • 支持属性序列化
  • 类型安全的数据转换

使用方法

1. 添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
yaserde = "0.8"
yaserde_derive = "0.8"

2. 基本使用示例

use yaserde_derive::{YaDeserialize, YaSerialize};

#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
    #[yaserde(attribute)]
    id: String,
    title: String,
    author: String,
    #[yaserde(rename = "pub_date")]
    publication_date: String,
}

fn main() {
    let book = Book {
        id: "1".to_string(),
        title: "Rust Programming".to_string(),
        author: "John Doe".to_string(),
        publication_date: "2023-01-01".to_string(),
    };

    // 序列化为XML
    let xml = yaserde::ser::to_string(&book).unwrap();
    println!("Serialized XML:\n{}", xml);

    // 反序列化回结构体
    let deserialized: Book = yaserde::de::from_str(&xml).unwrap();
    println!("Deserialized: {:?}", deserialized);
}

3. 输出示例

序列化后的XML可能如下:

<?xml version="1.0" encoding="utf-8"?>
<book id="1">
  <title>Rust Programming</title>
  <author>John Doe</author>
  <pub_date>2023-01-01</pub_date>
</book>

4. 高级配置选项

命名空间支持

#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
#[yaserde(
    rename = "book",
    namespace = "ns: http://example.com/namespace"
)]
pub struct Book {
    #[yaserde(attribute, prefix = "ns")]
    id: String,
    // ...
}

嵌套结构

#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
pub struct Library {
    #[yaserde(rename = "book")]
    books: Vec<Book>,
}

枚举支持

#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
pub enum BookType {
    #[yaserde(rename = "paperback")]
    Paperback,
    #[yaserde(rename = "hardcover")]
    Hardcover,
    #[yaserde(rename = "ebook")]
    EBook,
}

完整示例demo

下面是一个结合了上述所有特性的完整示例:

use yaserde_derive::{YaDeserialize, YaSerialize};

// 定义书籍类型枚举
#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
pub enum BookType {
    #[yaserde(rename = "paperback")]
    Paperback,
    #[yaserde(rename = "hardcover")]
    Hardcover,
    #[yaserde(rename = "ebook")]
    EBook,
}

// 定义书籍结构体,包含命名空间和属性
#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
#[yaserde(
    rename = "book",
    namespace = "ns: http://example.com/namespace"
)]
pub struct Book {
    #[yaserde(attribute, prefix = "ns")]
    id: String,
    title: String,
    author: String,
    #[yaserde(rename = "pub_date")]
    publication_date: String,
    #[yaserde(rename = "type")]
    book_type: BookType,
}

// 定义图书馆结构体,包含嵌套的书籍集合
#[derive(YaSerialize, YaDeserialize, PartialEq, Debug)]
pub struct Library {
    #[yaserde(rename = "book")]
    books: Vec<Book>,
}

fn main() {
    // 创建图书馆数据
    let library = Library {
        books: vec![
            Book {
                id: "1".to_string(),
                title: "Rust Programming".to_string(),
                author: "John Doe".to_string(),
                publication_date: "2023-01-01".to_string(),
                book_type: BookType::Paperback,
            },
            Book {
                id: "2".to_string(),
                title: "Advanced Rust".to_string(),
                author: "Jane Smith".to_string(),
                publication_date: "2023-02-15".to_string(),
                book_type: BookType::Hardcover,
            },
        ],
    };

    // 序列化为XML
    let xml = yaserde::ser::to_string(&library).unwrap();
    println!("Serialized XML:\n{}", xml);

    // 反序列化回结构体
    let deserialized: Library = yaserde::de::from_str(&xml).unwrap();
    println!("Deserialized: {:?}", deserialized);
}

注意事项

  1. 默认情况下,字段名会转换为小写作为XML标签名
  2. 可以使用#[yaserde(rename = "...")]自定义标签名
  3. 使用#[yaserde(attribute)]将字段序列化为XML属性而非子元素
  4. 对于Option类型,值为None时默认不会序列化

yaserde_derive提供了一种高效且类型安全的方式来处理Rust结构体与XML之间的转换,特别适合需要与XML接口交互的应用场景。

回到顶部