反序列化嵌套 JSON 结构时,Serde 返回 SyntaxError “预期值”

Posted

技术标签:

【中文标题】反序列化嵌套 JSON 结构时,Serde 返回 SyntaxError “预期值”【英文标题】:Serde returns a SyntaxError "expected value" when deserializing nested JSON structs 【发布时间】:2016-04-30 20:53:17 【问题描述】:

我正在尝试从 Web API (specifications) 反序列化 Spotify 元数据 JSON。我正在使用 hyper 从服务器中检索 JSON,并使用 serde 将 JSON 转换为我可以在 Rust 中实际使用的东西。从服务器检索 JSON 就好了,但是当我尝试将 JSON 转换为可以使用的对象时,Rust 恐慌并抛出错误:

thread '<main>' panicked at 'called 'Result::unwrap()' on an 'Err' value: SyntaxError("expected value", 11, 21)', ../src/libcore/result.rs:746

这一点用处都没有,因为它根本不指出哪里出了问题。在网上搜索时,我偶然发现了a serde issue,这让我认为问题与 JSON 的嵌套结构有关。

谁能看出哪里出了问题?修复错误对我来说是最好的解决方案,但如果另一个板条箱是一个更好的解决方案,我也想听听。我已经尝试过 rustc-serialize,但是那个 crate 无法处理 json 中的 'type' 变量。

我使用的代码是:

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
#![feature(custom_attribute)]

extern crate hyper;
extern crate serde;
extern crate serde_json;

use std::io::Read;
use hyper::Client;
use hyper::header::Connection;

#[derive(Serialize, Deserialize)]
struct Track_Full 
    album: Album_Simp,
    artists: Vec<Artist_Simp>,
    available_markets: Vec<String>,
    disc_number: u8,
    duration_ms: u32,
    explicit: bool,
    external_ids: External_IDs,
    external_urls: External_URLs,
    href: String,
    id: String,
    name: String,
    popularity: u8,
    preview_url: String,
    track_number: u8,
    #[serde(rename="type")]
    _type: String,
    uri: String


#[derive(Serialize, Deserialize)]
struct Album_Simp 
    album_type: String,
    available_markets: Vec<String>,
    external_urls: External_URLs,
    href: String,
    id: String,
    images: Vec<Image>,
    name: String,
    #[serde(rename="type")]
    _type: String,
    uri: String


#[derive(Serialize, Deserialize)]
struct Artist_Simp 
    external_urls: External_URLs,
    href: String,
    id: String,
    name: String,
    #[serde(rename="type")]
    _type: String,
    uri: String


#[derive(Serialize, Deserialize)]
struct External_IDs 
    isrc: String


#[derive(Serialize, Deserialize)]
struct External_URLs 
    spotify: String


#[derive(Serialize, Deserialize)]
struct Image 
    height: u8,
    url: String,
    width: u8


fn main() 
    // Create a client.
    let mut client = Client::new();

    // Creating an outgoing request.
    let mut res = client.get("https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem")
        // set a header
        .header(Connection::close())
        // let 'er go!
        .send().unwrap();

    // Read the Response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    println!("", body);

    let deserialized: Track_Full = serde_json::from_str(&body).unwrap();

JSON:


  "album" : 
    "album_type" : "album",
    "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ],
    "external_urls" : 
      "spotify" : "https://open.spotify.com/album/6TJmQnO44YE5BtTxH8pop1"
    ,
    "href" : "https://api.spotify.com/v1/albums/6TJmQnO44YE5BtTxH8pop1",
    "id" : "6TJmQnO44YE5BtTxH8pop1",
    "images" : [ 
      "height" : 640,
      "url" : "https://i.scdn.co/image/8e13218039f81b000553e25522a7f0d7a0600f2e",
      "width" : 629
    , 
      "height" : 300,
      "url" : "https://i.scdn.co/image/8c1e066b5d1045038437d92815d49987f519e44f",
      "width" : 295
    , 
      "height" : 64,
      "url" : "https://i.scdn.co/image/d49268a8fc0768084f4750cf1647709e89a27172",
      "width" : 63
     ],
    "name" : "Hot Fuss",
    "type" : "album",
    "uri" : "spotify:album:6TJmQnO44YE5BtTxH8pop1"
  ,
  "artists" : [ 
    "external_urls" : 
      "spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu"
    ,
    "href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu",
    "id" : "0C0XlULifJtAgn6ZNCW2eu",
    "name" : "The Killers",
    "type" : "artist",
    "uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu"
   ],
  "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ],
  "disc_number" : 1,
  "duration_ms" : 222075,
  "explicit" : false,
  "external_ids" : 
    "isrc" : "USIR20400274"
  ,
  "external_urls" : 
    "spotify" : "https://open.spotify.com/track/0eGsygTp906u18L0Oimnem"
  ,
  "href" : "https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem",
  "id" : "0eGsygTp906u18L0Oimnem",
  "name" : "Mr. Brightside",
  "popularity" : 74,
  "preview_url" : "https://p.scdn.co/mp3-preview/934da7155ec15deb326635d69d050543ecbee2b4",
  "track_number" : 2,
  "type" : "track",
  "uri" : "spotify:track:0eGsygTp906u18L0Oimnem"

【问题讨论】:

【参考方案1】:

您尝试解析一些 JSON,但失败了。当你在Result 上调用unwrap 时,程序因为这个失败而恐慌:

SyntaxError("expected value", 11, 21)

The documentation for SyntaxError 表示数字是错误的行和列。第 11 行第 21 列是:

      "height" : 640,
                     ^

查看您的结构,您已将高度声明为 u8,一个 8 位无符号数。这具有 0-255 的允许值。 640不适合这个。将值增加到 u32 允许解析 JSON。


此外,Rust 风格是使用 CamelCase 标识符而不是连续大写字母的结构。 External_URLs -> ExternalUrls。编译器实际上会就此发出警告。

【讨论】:

以上是关于反序列化嵌套 JSON 结构时,Serde 返回 SyntaxError “预期值”的主要内容,如果未能解决你的问题,请参考以下文章

Rust 和 Serde JSON 反序列化示例?

如何为计时时间戳使用自定义 serde 反序列化器?

错误:必须在此上下文(Rust)/ serde_json值中知道此值的类型

如何为 Hive 创建架构以使用 SerDe 解析深度嵌套的 json(Azure Application Insights 输出)?

Spring RestTemplate在尝试反序列化嵌套的对象列表时返回null对象

Golang basic_leaming结构体和 Json 相互转换序列化反序列化