Чтение XML файла в struct

Я пытаюсь написать программу, которая читает XML файл в ранее определенную структуру Rust.

Что-то вроде этого:

<?xml version="1.0" encoding="UTF-8"?>
<note name="title">
  <body name="main_body">
    <layer content_type="something" count="99">
      <data id="13">
        Datacontent
      </data>
    </layer>
  </body>
</note>

В это:

struct Note {
    name: String,
    Body: Body 
}

struct Body {
    name: String,
    layers: Vec<Layer>,
}

struct Layer {
    content_type: String,
    count: u8,
    data: Vec<Data>,
}

struct Data {
    id: u8,
    // Datacontent?
}

Я посмотрел на xml-rs, поскольку в настоящее время он является самой популярной библиотекой XML. Будучи новичком в Rust, мне трудно понять, как выполнить эту задачу.

Ответ 1

Rust прекрасно поддерживает автоматическую генерацию (де) кода сериализации. Там rustc-serialize которая требует очень мало настроек. Тогда есть serde crate, который является совершенно новой (де) платформой сериализации, которая допускает множество форматов и подробных пользовательских конфигураций, но требует немного более начальной настройки.

Я собираюсь описать, как использовать serde + serde_xml_rs десериализации XML к ржавчине структур.

Добавьте ящики к вашему Cargo.toml

Мы можем либо реализовать код десериализации вручную, либо мы можем сгенерировать его автоматически с помощью ящика serde_derive.

[dependencies]
serde_derive = "1.0"
serde = "1.0"
serde-xml-rs = "0.3.1"

Добавьте аннотации к своим структурам

Серде нужно знать о твоих структурах. Чтобы помочь этому, а не генерировать код для каждой отдельной структуры в вашем проекте, вам нужно аннотировать структуры, которые вы хотите. Debug является производной, поэтому мы можем легко напечатать структуры с помощью println! проверить, все ли работает. Deserialize - это то, что уведомляет serde для генерации кода. Если вы хотите трактовать содержимое тега xml как текст, вам необходимо "переименовать" поле, которое должно содержать текст, в $value. При создании ящика serde_xml_rs присвоено наименование $value очень произвольно, но оно никогда не может столкнуться с фактическим полем, поскольку имена полей не могут содержать знаки $.

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_xml_rs;

#[derive(Deserialize, Debug)]
struct Note {
    name: String,
    body: Body,
}

#[derive(Deserialize, Debug)]
struct Body {
    name: String,
    #[serde(rename="layer")]
    layers: Vec<Layer>,
}

#[derive(Deserialize, Debug)]
struct Layer {
    content_type: String,
    count: u8,
    data: Vec<Data>,
}

#[derive(Deserialize, Debug)]
struct Data {
    id: u8,
    #[serde(rename="$value")]
    content: String,
}

Превратите строку, содержащую xml, в объект

Теперь самое простое. Вы вызываете serde_xml::from_str в вашей строке и получаете либо ошибку, либо значение типа Node:

fn main() {
    let note: Note = serde_xml_rs::deserialize(r##"
<?xml version="1.0" encoding="UTF-8"?>
<note name="title">
  <body name="main_body">
    <layer content_type="something" count="99">
      <data id="13">
        Datacontent
      </data>
    </layer>
  </body>
</note>
    "##.as_bytes()).unwrap();
    println!("{:#?}", note);
}