Десериализуйте поле XML непосредственно в вариант единицы перечисления с тем же именем, используя quick_xml, serde

Контекст

При попытке найти более простой способ обработки приведения к типам ржавчины при чтении бинарного файла с использованием его XML-описания было предложено использовать перечисление с типами единиц измерения вместо десериализации строки или &str, чтобы получить больше гарантий от компилятор и избежать времени жизни; однако получение XML для десериализации непосредственно в варианты единиц перечисления вызывает некоторые проблемы.

XML-файл

<Records>
    <Record>
        <name>Single</name>
        <number>1</number>
        <location>0</location>
        <data_type>IEEE754LSBSingle</data_type>
        <length>4</length>
    </Record>
    <Record>
        <name>Double</name>
        <number>2</number>
        <location>4</location>
        <data_type>IEEE754LSBDouble</data_type>
        <length>8</length>
    </Record>
    <Record>
        <name>SingleArr</name>
        <number>3</number>
        <location>11</location>
        <data_type>IEEE754LSBSingleArr</data_type>
        <length>8</length>
    </Record>
    <Record>
        <name>DoubleArr</name>
        <number>4</number>
        <location>18</location>
        <data_type>IEEE754LSBDoubleArr</data_type>
        <length>16</length>
    </Record>
</Records>

Код

use binary_type_cast::PrettyPrint;
use quick_xml::{de::from_reader, DeError};
use serde::{Deserialize};
use std::{fs::File, io::BufReader};

#[derive(Clone, Copy, Debug, Deserialize)]
//#[serde(tag = "data_type")]
//#[serde(untagged)]
pub enum DataTypes {
    // 4 bytes
    IEEE754LSBSingle,
    // 8 bytes
    IEEE754LSBDouble,
    // [4 bytes, 4 bytes]
    IEEE754LSBSingleArr,
    // [8 bytes, 8 bytes]
    IEEE754LSBDoubleArr,
    // Include ASCIIString just to make sure records are still gathered even if none of them use this
    ASCIIString,
}

#[derive(Debug, Deserialize)]
pub struct Records {
    #[serde(rename = "Record")]
    pub records: Vec<Record>,
}

#[derive(Debug, Deserialize)]
pub struct Record {
    pub name: String,
    pub number: u32,
    pub location: u32,
    //#[serde(flatten)]
    pub data_type: DataTypes,
    pub length: u32
}

pub fn get_xml_record(file: &File) -> Result<Records, DeError> {
    let reader = BufReader::new(file);    
    let records: Records = from_reader(reader).unwrap();
    Ok(records)
}

fn main() {
    let description = "./data/desc.xml";
    if let Ok(file) = File::open(description) {
        if let Ok(records) = get_xml_record(&file) {
            println!("{:#?}",records);

        }
    }

}

Я попытался реализовать различные комбинации закомментированных атрибутов serde, которые можно увидеть в представленном коде. Похоже, что создание пользовательского десериализатора, который будет сопоставлять строку из XML, а затем выводить связанный вариант DataTypes, будет по существу повторять поведение исходного сообщения в другой проблеме, где строки сопоставлялись и преобразовывались вручную.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, это ошибка в quick-xml

Я заставил его работать без особой суеты, используя вместо этого serde-xml-rs:

use serde_xml_rs::from_str;
use serde::Deserialize;

#[derive(Clone, Copy, Debug, Deserialize)]
pub enum DataTypes {
    // 4 bytes
    IEEE754LSBSingle,
    // 8 bytes
    IEEE754LSBDouble,
    // [4 bytes, 4 bytes]
    IEEE754LSBSingleArr,
    // [8 bytes, 8 bytes]
    IEEE754LSBDoubleArr,
    // Include ASCIIString just to make sure records are still gathered even if none of them use this
    ASCIIString,
}

#[derive(Debug, Deserialize)]
pub struct Records {
    #[serde(rename = "$value")]
    pub records: Vec<Record>,
}

#[derive(Debug, Deserialize)]
pub struct Record {
    pub name: String,
    pub number: u32,
    pub location: u32,
    pub data_type: DataTypes,
    pub length: u32
}

fn main() {
    let source = r##"
<Records>
    <Record>
        <name>Single</name>
        <number>1</number>
        <location>0</location>
        <data_type>IEEE754LSBSingle</data_type>
        <length>4</length>
    </Record>
    <Record>
        <name>Double</name>
        <number>2</number>
        <location>4</location>
        <data_type>IEEE754LSBDouble</data_type>
        <length>8</length>
    </Record>
    <Record>
        <name>SingleArr</name>
        <number>3</number>
        <location>11</location>
        <data_type>IEEE754LSBSingleArr</data_type>
        <length>8</length>
    </Record>
    <Record>
        <name>DoubleArr</name>
        <number>4</number>
        <location>18</location>
        <data_type>IEEE754LSBDoubleArr</data_type>
        <length>16</length>
    </Record>
</Records>
    "##;

    let records: Records = from_str(source).unwrap();
    dbg!(records);
}

Вывод:

[src\main.rs:71] records = Records {
    records: [
        Record {
            name: "Single",
            number: 1,
            location: 0,
            data_type: IEEE754LSBSingle,
            length: 4,
        },
        Record {
            name: "Double",
            number: 2,
            location: 4,
            data_type: IEEE754LSBDouble,
            length: 8,
        },
        Record {
            name: "SingleArr",
            number: 3,
            location: 11,
            data_type: IEEE754LSBSingleArr,
            length: 8,
        },
        Record {
            name: "DoubleArr",
            number: 4,
            location: 18,
            data_type: IEEE754LSBDoubleArr,
            length: 16,
        },
    ],
}

Спасибо. Это также работает с from_reader

William 04.11.2022 00:27

Другие вопросы по теме