#Parsing (complicated structures of) XML using serde_xml_rs

4 messages · Page 1 of 1 (latest)

amber parrot
#

I don't really want to show the entire file (it's large) so here's the general structure:

<?xml version="1.0" encoding="utf-8"?>
<metalink>
 <files>
  <file name="repomd.xml">
   <mm0:timestamp>1651698971</mm0:timestamp>
   <size>6285</size>
   <verification>
    <hash type="md5">...</hash>
    <hash type="sha1">...</hash>
    ...
   </verification>
   <resources>
    <url protocol="https" type="https" location="JP" preference="100">https://url.to/repomd.xml</url>
    <url protocol="http" type="http" location="JP" preference="100">http://url.to/repomd.xml</url>
    ...
    <url protocol="rsync" type="rsync" location="SG" preference="92">rsync://url.to/repomd.xml</url>
   </resources>
  </file>
 </files>
</metalink>
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Metalink {
    #[serde(rename = "files")]
    pub files: Vec<File>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct File {
    pub name: String,
    pub size: i8,
    #[serde(rename = "hash")]
    pub verification: Vec<Hash>,
    pub resources: Vec<Url>,
}
...
#[tokio::main]
async fn main() {
    let resp = reqwest::get("https://mirrors.fedoraproject.org/metalink?repo=fedora-36&arch=x86_64")
        .await
        .unwrap()
        .text()
        .await
        .unwrap();
    let metalink: Metalink = from_str(&resp).unwrap();  // ERROR AT unwrap()
    let file = &metalink.files[0];
    assert_eq!(file.name, "repomd.xml")
}

Running the program:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { field: "missing field `name`" }', anda-server/src/main.rs:101:46

Objective:
Parse the xml file downloaded correctly, and include both the url (https://url.to/repomd.xml) and the type ("https") and etc.

bright berry
#
  • There's a peculiarity with that crate iirc, where you have to have a wrapper type for each field that contains multiple elements. So for example:
#[derive(Debug, Deserialize)]
pub struct Metalink {
    pub files: Files, // name of the encompassing element
}

#[derive(Debug, Deserialize)]
pub struct Files {
    #[serde(rename = "file")] // name of a singular element on the inside
    pub files: Vec<File>,
}
```Unless I'm mistaken or this has been updated, you have to do this for it to find the fields, like `name` in this case.

Also do this for e.g. `verification` and `resources` fields.

- `size` on your `File` will overflow (use a bigger integer)

- You likely don't need `Serialize` given that you only deserialize, also Idk about `PartialEq`, you rarely want to compare humongous types
amber parrot
#

oh so you have to make a struct for the tag and then have vec as attr inside the struct

#

alright