问题描述
我正在尝试在 Rust 中使用 Serde 和 Quick-XML 反序列化 MathML。由于 MathML 的递归性质,我在尝试编写结构时遇到了麻烦。这是一个最小的、可重现的示例:
/// REQUIRES: outputs is not nullptr if `output_tensor_names` is non-empty.
virtual Status Run(const std::vector<std::pair<string,Tensor> >& inputs,const std::vector<string>& output_tensor_names,const std::vector<string>& target_node_names,std::vector<Tensor>* outputs) = 0;
存在堆栈溢出,可能是由于here 和here 建议的无限循环所致。我试图实施他们的建议,但无济于事。
解决方法
这是一个关于如何使用 serde 解析嵌套 XML 结构的示例。此代码基于 this 答案。示例 XML 具有称为测量值的节点,该节点放置在 Vec<structs::Data>
中。
Cargo.toml:
[dependencies]
serde_derive = "1.0"
serde = "1.0"
serde-xml-rs = "0.4"
serde_json = "1.0.64"
structs.rs:
// XML-root
#[derive(Deserialize,Debug)]
pub(crate) struct D2LogicalModel {
pub(crate) payloadPublication: PayloadPublication,}
// payloadPublication
#[derive(Deserialize,Debug)]
pub(crate) struct PayloadPublication {
lang: String,pub(crate) publicationTime: PublicationTime,pub(crate) siteMeasurements: Vec<SiteMeasurements>,}
#[derive(Deserialize,Debug)]
pub(crate) struct PublicationTime {
#[serde(rename = "$value")]
pub(crate) publicationTime: String,}
// // siteMeasurements,the various weather measurements are below (sub-root).
#[derive(Deserialize,Debug)]
pub(crate) struct SiteMeasurements {
pub(crate) measurementSiteReference: MeasurementSiteReference,pub(crate) measurementTimeDefault: MeasurementTimeDefault,#[serde(default)]
pub(crate) measuredValue: Vec<MeasuredValue_>,Debug)]
pub(crate) struct MeasurementSiteReference {
pub(crate) id: u16,targetClass: String,version: u16,Debug)]
pub(crate) struct MeasurementTimeDefault {
#[serde(rename = "$value")]
pub(crate) measurementTimeDefault: String,}
// Common for all measurements.
#[derive(Deserialize,Debug)]
pub(crate) struct MeasuredValue_ {
pub(crate) index: u16,pub(crate) measuredValue: MeasuredValue,Debug)]
pub(crate) struct MeasuredValue {
pub(crate) basicData: BasicData,}
// Split based on type of measurement. Below this point the tree is different.
#[derive(Deserialize,Debug,Default)]
pub(crate) struct BasicData {
#[serde(default)]
pub(crate) precipitationDetail: PrecipitationDetail,#[serde(default)]
pub(crate) wind: Wind,#[serde(default)]
pub(crate) temperature: Temperature_,// Add underscore since this collides with another struct
}
// precipitationIntensity
#[derive(Deserialize,Default)]
pub(crate) struct PrecipitationDetail {
#[serde(default)]
pub(crate) precipitationIntensity: PrecipitationIntensity,Default)]
pub(crate) struct PrecipitationIntensity {
#[serde(default = "precipitation_intensity")]
pub(crate) field_description: String,#[serde(default)]
pub(crate) millimetresPerHourIntensity: MillimetresPerHourIntensity,Default)]
pub(crate) struct MillimetresPerHourIntensity {
#[serde(rename = "$value")]
pub(crate) millimetresPerHourIntensity: f32,Default)]
pub(crate) struct Temperature {
#[serde(rename = "$value")]
pub(crate) temperature: f32,}
// windSpeed
#[derive(Deserialize,Default)]
pub(crate) struct Wind {
#[serde(default)]
pub(crate) windSpeed: WindSpeed,Default)]
pub(crate) struct WindSpeed {
#[serde(default = "wind_speed")]
pub(crate) field_description: String,#[serde(default)]
pub(crate) speed: Speed,Default)]
pub(crate) struct Speed {
#[serde(rename = "$value")]
pub(crate) speed: f32,}
// airTemperature
#[derive(Deserialize,Default)]
pub(crate) struct Temperature_ {
#[serde(default)]
pub(crate) airTemperature: AirTemperature,Default)]
pub(crate) struct AirTemperature {
#[serde(default = "air_temperature")]
pub(crate) field_description: String,#[serde(default)]
pub(crate) temperature: Temperature,}
// Add default values in serde.
fn precipitation_intensity() -> String {
"precipitation_intensity".to_string()
}
fn wind_speed() -> String {
"wind_speed".to_string()
}
fn air_temperature() -> String {
"air_temperature".to_string()
}
#[derive(Serialize)]
pub(crate) struct WeatherMeasurement {
pub(crate) measurement_time_default: String,pub(crate) id: u16,pub(crate) data: Vec<Data>,}
#[derive(Serialize)]
pub(crate) struct Data {
pub(crate) index: u16,pub(crate) field_description: String,pub(crate) measurement: f32,}
main.rs:
#![allow(non_snake_case)]
mod structs;
use std::fs;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_xml_rs;
fn main() -> Result<(),Box<dyn std::error::Error>> {
println!("Goodbye XML!");
let filename = "./sample.xml";
let content= fs::read_to_string(filename).expect("Unable to read file");
let d2LogicalModel: structs::D2LogicalModel = serde_xml_rs::from_str(&*content).unwrap();
let mut measurements: Vec<structs::WeatherMeasurement> = Vec::new();
for site in &d2LogicalModel.payloadPublication.siteMeasurements {
// The actual weather data
let mut readings: Vec<structs::Data> = Vec::new();
let measurement_time_default = &site.measurementTimeDefault.measurementTimeDefault;
let id = &site.measurementSiteReference.id;
for measured_value in &site.measuredValue {
let index = &measured_value.index;
let weather_node = &measured_value.measuredValue.basicData;
// precipitationIntensity
let field_description = &weather_node
.precipitationDetail
.precipitationIntensity
.field_description;
if !field_description.is_empty() {
let measurement = &weather_node
.precipitationDetail
.precipitationIntensity
.millimetresPerHourIntensity
.millimetresPerHourIntensity;
let r = structs::Data {
index: *index,field_description: field_description.clone(),measurement: *measurement,};
readings.push(r);
/*println!("measurement time-default: {},id: {},index: {},field description: {},measurement: {}",measurement_time_default,id,index,field_description,measurement);*/
};
// windSpeed
let field_description = &weather_node.wind.windSpeed.field_description;
if !field_description.is_empty() {
let measurement = &weather_node.wind.windSpeed.speed.speed;
let r = structs::Data {
index: *index,measurement);*/
};
// airTemperature
let field_description = &weather_node.temperature.airTemperature.field_description;
if !field_description.is_empty() {
let measurement = &weather_node
.temperature
.airTemperature
.temperature
.temperature;
let r = structs::Data {
index: *index,measurement);*/
};
}
let wm = structs::WeatherMeasurement {
measurement_time_default: measurement_time_default.clone(),id: *id,data: readings,};
measurements.push(wm);
// Add final struct here
}
let jm = serde_json::to_string(&measurements)?;
println!("{:?}",&jm);
Ok(())
}
sample.xml:
<d2LogicalModel modelBaseVersion="2" xmlns="http://datex2.eu/schema/2/2_0">
<payloadPublication lang="nob" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="MeasuredDataPublication">
<publicationTime>2021-03-24T21:02:28.762+01:00</publicationTime>
<siteMeasurements>
<measurementSiteReference id="228" targetClass="MeasurementSiteRecord" version="3576"/>
<measurementTimeDefault>2021-03-24T20:50:00+01:00</measurementTimeDefault>
<measuredValue index="2501">
<measuredValue>
<basicData xsi:type="PrecipitationInformation">
<precipitationDetail>
<precipitationIntensity>
<millimetresPerHourIntensity>0.0</millimetresPerHourIntensity>
</precipitationIntensity>
</precipitationDetail>
</basicData>
</measuredValue>
</measuredValue>
<measuredValue index="901">
<measuredValue>
<basicData xsi:type="WindInformation">
<wind>
<windSpeed>
<speed>21.24</speed>
</windSpeed>
</wind>
</basicData>
</measuredValue>
</measuredValue>
<measuredValue index="101">
<measuredValue>
<basicData xsi:type="TemperatureInformation">
<temperature>
<airTemperature>
<temperature>0.2</temperature>
</airTemperature>
</temperature>
</basicData>
</measuredValue>
</measuredValue>
</siteMeasurements>
</payloadPublication>
</d2LogicalModel>