Deserializing XML

I'm trying to deserialize the following xml data:

<?xml version="1.0" encoding="UTF-8"?>
<wfs:FeatureCollection
  timeStamp="2022-11-11T14:52:17Z"
  numberReturned="100"
  numberMatched="100"
  xmlns:wfs="http://www.opengis.net/wfs/2.0"
  xmlns:gml="http://www.opengis.net/gml/3.2"
  xmlns:BsWfs="http://xml.fmi.fi/schema/wfs/2.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd
                        http://xml.fmi.fi/schema/wfs/2.0 https://xml.fmi.fi/schema/wfs/2.0/fmi_wfs_simplefeature.xsd">

    <wfs:member>
        <BsWfs:BsWfsElement gml:id="BsWfsElement.1.1.1">
            <BsWfs:Location>
                <gml:Point gml:id="BsWfsElementP.1.1.1" srsDimension="2" srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
                    <gml:pos>60.22924 24.96403 </gml:pos>
                </gml:Point>
            </BsWfs:Location>
            <BsWfs:Time>2022-11-11T15:00:00Z</BsWfs:Time>
            <BsWfs:ParameterName>WeatherSymbol3</BsWfs:ParameterName>
            <BsWfs:ParameterValue>3.0</BsWfs:ParameterValue>
        </BsWfs:BsWfsElement>
    </wfs:member>
	
    <wfs:member>
        <BsWfs:BsWfsElement gml:id="BsWfsElement.1.1.2">
            <BsWfs:Location>
                <gml:Point gml:id="BsWfsElementP.1.1.2" srsDimension="2" srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
                    <gml:pos>60.22924 24.96403 </gml:pos>
                </gml:Point>
            </BsWfs:Location>
            <BsWfs:Time>2022-11-11T15:00:00Z</BsWfs:Time>
            <BsWfs:ParameterName>Temperature</BsWfs:ParameterName>
            <BsWfs:ParameterValue>11.6</BsWfs:ParameterValue>
        </BsWfs:BsWfsElement>
    </wfs:member>
</wfs:FeatureCollection>

This data goes on for about 1200 lines, but the structure remains the same. However, I can't manage to deserialize it. This is what I've got so far:

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsFeatureCollection {
    #[serde(rename = "$value")]
    pub member: Vec<WfsMember>,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsMember {
    #[serde(rename = "$value")]
    pub element: WfsElement,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsElement {
    #[serde(rename = "$value")]
    pub location: WfsLocation,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsLocation {
    #[serde(rename = "$value")]
    pub point: GmlPoint,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct GmlPoint {
    #[serde(rename = "$value")]
    pub pos: GmlPos,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct GmlPos {
    #[serde(rename = "$value")]
    pub coordinates: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsTime {
    #[serde(rename = "$value")]
    pub time: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsParameterName {
    #[serde(rename = "$value")]
    pub name: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsParameterValue {
    #[serde(rename = "$value")]
    pub value: String,
}

Unfortunately, all I get is this error: duplicate field $value. Where exactly is the duplicate? Every struct has only one of those fields. How can I deserialize the data properly? I am using quick-xml with the serialize feature. Any help would be greatly appreciated!

(If it's still relevant to you) I've got it working with the following definitions:

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsFeatureCollection {
    #[serde(rename = "$value")]
    pub members: Vec<WfsMember>,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WfsMember {
    #[serde(rename = "$value")]
    pub element: BsWfsElement,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct BsWfsElement {
    #[serde(rename = "Location")]
    pub location: Location,
    #[serde(rename = "Time")]
    pub time: Time,
    #[serde(rename = "ParameterName")]
    pub param_name: ParameterName,
    #[serde(rename = "ParameterValue")]
    pub param_value: ParameterValue,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct Location {
    #[serde(rename = "$value")]
    pub point: GmlPoint,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct GmlPoint {
    #[serde(rename = "$value")]
    pub pos: GmlPos,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct GmlPos {
    #[serde(rename = "$value")]
    pub coordinates: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct Time {
    #[serde(rename = "$value")]
    pub time: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct ParameterName {
    #[serde(rename = "$value")]
    pub name: String,
}

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct ParameterValue {
    #[serde(rename = "$value")]
    pub value: String,
}

The chief difference is the definition of BsWfsElement, which breaks the sequence of $values and defines the contents of an element as the sequence of its constituent parts. Struct names are a mishmash of namespace-qualified and unqualified, which I wouldn't keep in production code.

1 Like

It is indeed still relevant! I honestly can't thank you enough, you literally saved me with this one!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.