【问题标题】:Trying to parse JSON in Java (using Gson), getting MalformedJsonException尝试在 Java 中解析 JSON(使用 Gson),得到 MalformedJsonException
【发布时间】:2016-06-26 13:04:41
【问题描述】:

我正在尝试从 WeatherUnderground API 获取天气预报数据。

到目前为止,我正在使用以下代码:

URLConnection connection = url.openConnection();
connection.setConnectTimeout(5000);
connection.connect();

JsonParser jp = new JsonParser();

JsonElement forecastJson = jp.parse(new InputStreamReader((InputStream) connection.getContent())).getAsJsonObject()
        .getAsJsonObject().get("forecast")
        .getAsJsonObject().get("simpleforecast")
        .getAsJsonObject().getAsJsonArray("forecastday").get(1);

System.out.println("forecastJson = " + forecastJson.toString());

String date = String.valueOf(jp.parse(forecastJson
        .getAsJsonObject().get("date")
        .getAsJsonObject().get("epoch").getAsString()));

String high = String.valueOf(jp.parse(forecastJson
        .getAsJsonObject().get("high")
        .getAsJsonObject().get("celsius").getAsString()));

String low = String.valueOf(jp.parse(forecastJson
        .getAsJsonObject().get("low")
        .getAsJsonObject().get("celsius").getAsString()));

String conditions;
try {
    conditions = String.valueOf(jp.parse(forecastJson
            .getAsJsonObject().get("conditions").getAsString()));
} catch (JsonSyntaxException e) {
    e.printStackTrace();
}

我收到的 JsonElement forecastJson" 看起来像这样:

{
  "date": {
    "epoch": "1467046800",
    "pretty": "7:00 PM CEST on June 27, 2016",
    "day": 27,
    "month": 6,
    "year": 2016,
    "yday": 178,
    "hour": 19,
    "min": "00",
    "sec": 0,
    "isdst": "1",
    "monthname": "June",
    "monthname_short": "Jun",
    "weekday_short": "Mon",
    "weekday": "Monday",
    "ampm": "PM",
    "tz_short": "CEST",
    "tz_long": "Europe/Berlin"
  },
  "period": 2,
  "high": {
    "fahrenheit": "77",
    "celsius": "25"
  },
  "low": {
    "fahrenheit": "58",
    "celsius": "14"
  },
  "conditions": "Partly Cloudy",
  "icon": "partlycloudy",
  "icon_url": "http://icons.wxug.com/i/c/k/partlycloudy.gif",
  "skyicon": "",
  "pop": 0,
  "qpf_allday": {
    "in": 0,
    "mm": 0
  },
  "qpf_day": {
    "in": 0,
    "mm": 0
  },
  "qpf_night": {
    "in": 0,
    "mm": 0
  },
  "snow_allday": {
    "in": 0,
    "cm": 0
  },
  "snow_day": {
    "in": 0,
    "cm": 0
  },
  "snow_night": {
    "in": 0,
    "cm": 0
  },
  "maxwind": {
    "mph": 15,
    "kph": 24,
    "dir": "W",
    "degrees": 260
  },
  "avewind": {
    "mph": 11,
    "kph": 18,
    "dir": "W",
    "degrees": 260
  },
  "avehumidity": 48,
  "maxhumidity": 0,
  "minhumidity": 0
}

我能够获得“日期”、“高”和“低”字符串,但我无法获得“条件”,而且我不明白我做错了什么。

我收到以下异常:

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON

据我了解,JSON 没有格式错误。我应该如何获得“条件”值?

我也尝试过其他 JSON 解析器/库,但没有成功。我想继续使用 Gson-Library,我想我已经很接近了,但是卡住了。

感谢您的帮助。

【问题讨论】:

  • 顺便说一句,异常说“使用 JsonReader.setLenient(true) 接受格式错误的 JSON”,但就像我写的那样,我没有看到 JSON 格式错误,除此之外我没有创建任何地方的 JsonReader,所以我不知道什么时候可以应用“setLenient(true)。
  • 我不明白你的代码。为什么要解析整个 JSON,然后尝试重新解析其所有元素?解析 JSON,然后访问其元素。无需重新解析它们。
  • 为什么不为json数据创建一个类并使用TheClass foo = gson.fromJson(theJson, TheClass.class)然后使用foo
  • @JB Nizet:我是 Java 和 Json 的初学者,所以是的,我实际上认为我每次都需要解析 JSON 以从中获取一些东西。你的问题让我意识到我做错了。感谢您的帮助,我现在也得到了“条件”!
  • @RC.: 好的,我要试试,看起来是个好方法。就像我已经在我的其他评论中写的一样,我是初学者,所以这就是“你为什么不......”的答案:-)

标签: java json parsing gson


【解决方案1】:

如果您分解引发异常的行,您可以看到您实际上是在尝试将一个实际上 不是 JSON 的字符串解析为 JSON。

try {
    JsonObject jo = forecastJson.getAsJsonObject();
    JsonElement je = jo.get("conditions");
    String s1 = je.getAsString();

    // at this point s1 contains the value "Partly Cloudy" which you 
    // are trying to parse as JSON.
    JsonElement je2  = jp.parse(s1);


    conditions = String.valueOf(je2);
} catch (JsonSyntaxException e) {
    e.printStackTrace();
}

【讨论】:

    【解决方案2】:

    正如“JB Nizet”在我的问题下的评论中指出的那样,当我想获得另一部分内容时,我每次都试图再次解析 JSON。那是我(初学者)的错误。

    现在我只解析一次,然后直接获取内容,没有任何问题:

    JsonParser jp = new JsonParser();
    
    JsonElement forecastJson = jp.parse(new InputStreamReader((InputStream) connection.getContent())).getAsJsonObject()
            .getAsJsonObject().get("forecast")
            .getAsJsonObject().get("simpleforecast")
            .getAsJsonObject().getAsJsonArray("forecastday").get(1);
    
    String date = forecastJson.getAsJsonObject().get("date")
            .getAsJsonObject().get("epoch").getAsString();
    
    String high = forecastJson.getAsJsonObject().get("high")
            .getAsJsonObject().get("celsius").getAsString();
    
    String low = forecastJson.getAsJsonObject().get("low")
            .getAsJsonObject().get("celsius").getAsString();
    
    String conditions = forecastJson.getAsJsonObject()
            .get("conditions").getAsString();
    

    【讨论】:

      【解决方案3】:

      首先,正如他们在 cmets 中所说,实际上没有必要再次解析每个片段。

      String date = String.valueOf(jp.parse(forecastJson .getAsJsonObject().get("date") .getAsJsonObject().get("epoch").getAsString())); 是相同的: String date = forecastJson.getAsJsonObject().get("date") .getAsJsonObject().get("epoch").getAsString();

      您遇到的问题实际上是我怀疑是 Gson 库中的错误。当它试图解析一个带有空格的字符串时,它将对该字符串进行标记,并期望在第一个单词之后(在这种情况下为 Partly),文档应该结束并且 json 格式错误,因为它没有'没有到达文档的末尾。

      所以要解决这个问题,要么按照 cmets 的说法去做,这在你的情况下是合理的。或者,如果您不想,您可以随时将 Partly cloudy 更改为例如 Partly_cloudy,它会起作用 :)

      【讨论】:

      • @JJF 没关系我已经在本地测试过并查看了 GSON 源代码,我认为我的回答非常正确。在您的回答中,您说尝试解析字符串是不正确的,但这就是在异常发生之前几次之前发生的事情。您也可以尝试将字符串“Partly cloudy”放入 jsonlint.com,看看会发生什么。
      • 我确实将他的数据粘贴到 JSON lint 中,并且验证正常。此外,他的代码中没有其他地方试图解析无效的 json。每次对 .parse() 的调用都会在有效 JSON 上调用以获取嵌套元素的值。他只是调用了一个他不需要的 .parse() ,因为在最后一种情况下没有进一步的嵌套对象。 GSON 中明显且致命的错误在我看来不太可能。
      • @JJF 是的,之前的每个调用都是对有效的 json 的,但它们仍然是字符串,唯一的区别是之前的字符串中没有空格。 date.epoch 是一个字符串,high.celciuslow.celcius 也是字符串,无论是在 json 中还是从 getAsString 开始显式() 被调用。
      猜你喜欢
      • 2012-04-21
      • 2012-11-07
      • 2011-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 2011-07-26
      相关资源
      最近更新 更多