首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用serde / serde- XML -rs处理格式错误的xml

使用serde / serde- XML -rs处理格式错误的xml
EN

Stack Overflow用户
提问于 2021-09-09 16:59:31
回答 1查看 121关注 0票数 0

如果您曾经使用过serdeserde-xml-rs,那么您一定见过the sample code。他们的所有示例代码总是upwrap()s from_reader()函数调用。但是,如果我们需要像下面的扩展示例代码那样实际处理错误,会发生什么呢?

Cargo.toml

代码语言:javascript
复制
[package]
name = "so-help"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = "1.0.130"
serde_derive = "1.0.130"
serde-xml-rs = "0.5.0"

src/main.rs

代码语言:javascript
复制
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_xml_rs;

use serde_xml_rs::from_reader;

#[derive(Debug, Deserialize)]
struct Item {
    pub name: String,
    pub source: String
}

#[derive(Debug, Deserialize)]
struct Project {
    pub name: String,

    #[serde(rename = "Item", default)]
    pub items: Vec<Item>
}

fn main() {
    let correct = r##"
        <Project name="my_project">
            <Item name="hello" source="world.rs" />
        </Project>
    "##;
    let project: Project = from_reader(correct.as_bytes()).unwrap();
    println!("{:#?}", project);

    let malformed = r##"
        <Project name="malformed">
            <malformed name="Hello" source="world.rs />
            <WeDontClose This>
        </Project>
    "##;
    let messedup: Project = from_reader(malformed.as_bytes()).unwrap();
    println!("{:#?}", messedup);
}

malformed变量包含格式错误的XML数据,这些数据会导致from_reader()返回错误,但是由于示例总是使用unwrap(),因此没有解释如何处理这种错误状态。所以当我们运行我们的代码时,我们得到...

代码语言:javascript
复制
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/so-help`
Project {
    name: "my_project",
    items: [
        Item {
            name: "hello",
            source: "world.rs",
        },
    ],
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Syntax { source: Error { pos: 4:13, kind: Syntax("Unexpected token inside attribute value: <") } }', src/main.rs:37:63
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

我想要做的是使用惯用的rust语义通过match语句来处理错误。所以我试着通过替换这一行来处理这个错误...

代码语言:javascript
复制
    let messedup: Project = from_reader(malformed.as_bytes()).unwrap();

..。用这些台词..。

代码语言:javascript
复制
    let messedup: Project = match from_reader(malformed.as_bytes())
    {
        Ok(v) => v,
        Err(e) => println!("Error reading malformed xml {:?}", e),
    };

..。但是我得到了这个编译时错误...

代码语言:javascript
复制
$ cargo run
   Compiling so-help v0.1.0 (/home/dygear/so-help)
error[E0308]: mismatched types
  --> src/main.rs:40:19
   |
40 |         Err(e) => println!("Error reading malformed xml {:?}", e),
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Project`, found `()`
   |
   = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.
error: could not compile `so-help` due to previous error

那么我应该如何处理解析错误呢?我问过关于铁锈不和谐的问题,但似乎没有人对此有答案。问题似乎是由于使用的数据类型造成的,但我希望返回该数据类型,或者返回错误。

示例代码也是available on github的,因此您可以确切地看到我所在的位置

尝试@Lagerbaer的代码实际上并不起作用。

代码语言:javascript
复制
fn main() {
    let correct = r##"
        <Project name="my_project">
            <Item name="hello" source="world.rs" />
        </Project>
    "##;
    let project: Project = from_reader(correct.as_bytes()).unwrap();
    println!("{:#?}", project);

    let malformed = r##"
        <Project name="malformed">
            <malformed name="Hello" source="world.rs />
            <WeDontClose This>
        </Project>
    "##;
    let potentially_messed_up: Result<Project, serde_xml_rs::Error> = from_reader(malformed.as_bytes());
    if let Err(e) = potentially_messed_up {
        println!("Error reading malformed xml {:?}", e);
    } else {
        // now here we do stuff that we _only_ do if there's no error
        potentially_messed_up.unwrap();
        // here we can unwrap without ever causing a panic, because the 
        // if let Err(e) part made sure that we don't enter this branch if 
        // there was an error
    }
    println!("{:#?}", potentially_messed_up);
}

产生以下错误:

代码语言:javascript
复制
error[E0282]: type annotations needed for `Result<T, serde_xml_rs::Error>`
  --> src/main.rs:42:13
   |
37 |     let potentially_messed_up = from_reader(malformed.as_bytes());
   |         --------------------- consider giving `potentially_messed_up` the explicit type `Result<T, serde_xml_rs::Error>`, with the type parameters specified
...
42 |         let v = potentially_messed_up.unwrap();
   |             ^ cannot infer type

error: aborting due to previous error

所以我们现在把37行改成这样...

代码语言:javascript
复制
    let potentially_messed_up: Result<Project, serde_xml_rs::Error> = from_reader(malformed.as_bytes());

..。生成此错误...

代码语言:javascript
复制
error[E0382]: borrow of moved value: `potentially_messed_up`
    --> src/main.rs:47:23
     |
37   |     let potentially_messed_up: Result<Project, serde_xml_rs::Error> = from_reader(malformed.as_bytes());
     |         --------------------- move occurs because `potentially_messed_up` has type `Result<Project, serde_xml_rs::Error>`, which does not implement the `Copy` trait
...
42   |         potentially_messed_up.unwrap();
     |                               -------- `potentially_messed_up` moved due to this method call
...
47   |     println!("{:#?}", potentially_messed_up);
     |                       ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
     |
note: this function takes ownership of the receiver `self`, which moves `potentially_messed_up`
help: consider calling `.as_ref()` to borrow the type's contents
     |
42   |         potentially_messed_up.as_ref().unwrap();
     |                               ^^^^^^^^^

error: aborting due to previous error

所以我们改变这里的语句...

代码语言:javascript
复制
    let potentially_messed_up: Result<Project, serde_xml_rs::Error> = from_reader(malformed.as_bytes());
    if let Err(ref e) = potentially_messed_up {
        println!("Error reading malformed xml {:?}", e);
    } else {
        // now here we do stuff that we _only_ do if there's no error
        potentially_messed_up.as_ref().unwrap();
        // here we can unwrap without ever causing a panic, because the 
        // if let Err(e) part made sure that we don't enter this branch if 
        // there was an error
    }
    println!("{:#?}", potentially_messed_up);

在某种程度上是可行的,当存在时处理Err,但当没有时返回一个Ok包装的Project。这也不太正确。

代码语言:javascript
复制
Project {
    name: "my_project",
    items: [
        Item {
            name: "hello",
            source: "world.rs",
        },
    ],
}
Ok(
    Project {
        name: "my_project",
        items: [
            Item {
                name: "hello",
                source: "world.rs",
            },
        ],
    },
)

@Jmb下面的评论包含了一个要点,我遵循这个要点是为了更接近惯用的锈蚀,但我似乎也不能让它起作用。它会处理格式错误的输入错误,也会在Err匹配臂中处理正确的输入。这很奇怪,因为它直接在上面被正确读取。

代码语言:javascript
复制
fn main() {
    let correct = r##"
        <Project name="my_project">
            <Item name="hello" source="world.rs" />
        </Project>
    "##;
    let project: Project = from_reader(correct.as_bytes()).unwrap();
    println!("{:#?}", project);

    let malformed = r##"
        <Project name="malformed">
            <malformed name="Hello" source="world.rs />
            <WeDontClose This>
        </Project>
    "##;

    let correct = r##"
        <Project name="my_project">
            <Item name="hello" source="world.rs" />
        </Project>
    "##;
    let xml = match from_reader(correct.as_bytes())
    {
        Err (e) =>
        {
            println!("Error reading malformed xml {:?}", e);
            return
        }
        Ok(xml) =>
        {
            xml
        }
    };
    println!("{:?}", xml);
}
代码语言:javascript
复制
warning: unused variable: `malformed`
  --> src/main.rs:31:9
   |
31 |     let malformed = r##"
   |         ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_malformed`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.22s
     Running `target/debug/so-help`
Project {
    name: "my_project",
    items: [
        Item {
            name: "hello",
            source: "world.rs",
        },
    ],
}
Error reading malformed xml UnexpectedToken { token: "&XmlEvent::EndElement { .. }", found: "StartElement(Item, {\"\": \"\", \"xml\": \"http://www.w3.org/XML/1998/namespace\", \"xmlns\": \"http://www.w3.org/2000/xmlns/\"}, [name -> hello, source -> world.rs])" }
EN

回答 1

Stack Overflow用户

发布于 2021-09-09 17:26:45

我很惊讶你没有得到答案,因为它应该是相对简单的。

您的代码不能编译,因为您使用匹配表达式将值赋给类型为Project的变量,但只有一个匹配臂实际返回该类型的值,而另一个匹配臂不返回任何内容,它只是打印内容。

让我们放轻松,一步一步来。unwrapResult枚举的一种方法,正如您所知道的,它的行为是,如果值存在,则只返回值,如果出现错误,则返回异常。

因此,如果我们删除unwrap,剩下的就是一个Result枚举。这就是您处理错误所需的全部内容,当然,现在您必须决定如何处理错误。在您的示例中,您将打印一条错误消息。但之后会发生什么呢?下面是你可以做的:

代码语言:javascript
复制
let potentially_messed_up = from_reader(malformed.as_byes());
if let Err(e) = potentially_messed_up {
  println!("Error reading malformed xml {:?}", e);
} else {
  // now here we do stuff that we _only_ do if there's no error
  let v = potentially_messed_up.unwrap();
  // here we can unwrap without ever causing a panic, because the 
  // if let Err(e) part made sure that we don't enter this branch if 
  // there was an error
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69122148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档