JsonReader - 读取数组抛出预期名称但为 NULL

Posted

技术标签:

【中文标题】JsonReader - 读取数组抛出预期名称但为 NULL【英文标题】:JsonReader - reading an array throws Expected a name but was NULL 【发布时间】:2016-11-06 16:54:36 【问题描述】:

我正在使用 JsonReader 来解析一些 JSON 数据。这是一个结构相似的元素的大数组:

[  
     
      "type":"duel",
      "discipline":"leagueoflegends",
      "tournament_id":"57ee13fe140ba0cd2a8b4593",
      "opponents":[  
           
            "participant":null,
            "forfeit":false,
            "number":1,
            "result":1,
            "score":3
         ,
           
            "participant":null,
            "forfeit":false,
            "number":2,
            "result":3,
            "score":2
         
      ],
      "id":"58078b2770cb49c45b8b45bf",
      "status":"completed",
      "number":1,
      "stage_number":1,
      "group_number":1,
      "round_number":1,
      "date":"2016-10-01T05:00:00+0300",
      "timezone":"Europe/Helsinki",
      "match_format":null
   ,
   ...
]

这个数组中有数百个类似的元素。我只需要每个元素的一些数据,我编写了类似于this的代码:

public List<Match> readJsonStream(InputStream in) throws IOException 
    JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
    try 
        return readMatchesArray(reader);
     finally 
        reader.close();
    


public List<Match> readMatchesArray(JsonReader reader) throws IOException 
    List<Match> matches = new ArrayList<>();

    reader.beginArray();
    while (reader.hasNext()) 
        matches.add(readMatch(reader));
    
    reader.endArray();
    return matches;


public Match readMatch(JsonReader reader) throws IOException 
    String status = null, date = null, time = null;
    Match.Bracket bracket = null;
    int id = -1, round = -1;
    Match.Team team1 = null, team2 = null;

    reader.beginObject();
    while (reader.hasNext()) 
        String name = reader.nextName();
        switch (name) 
            case "number":
                id = reader.nextInt();
                break;
            case "status":
                status = reader.nextString().toUpperCase();
                break;
            case "group_number":
                if (reader.nextInt() == 1) 
                    bracket = WINNERS;
                 else if (reader.nextInt() == 2) 
                    bracket = LOSERS;
                
                break;
            case "round_number":
                round = reader.nextInt();
                break;
            case "date":
                try 
                    String tempDateRaw = reader.nextString();
                    String[] tempDate = tempDateRaw.split("T");
                    String[] tempTime = tempDate[1].split(":");

                    date = tempDate[0];
                    time = tempTime[0] + ":" + tempTime[1];
                 catch (IllegalStateException e) 
                    date = null;
                    time = null;
                
                break;
            case "opponents":
                int counter = 0;
                reader.beginArray();
                while (reader.hasNext()) 
                    if (counter == 0) 
                        team1 = readTeam(reader);
                     else 
                        team2 = readTeam(reader);
                    
                    counter++;
                
                reader.endArray();
                break;
            default:
                reader.skipValue();
                break;
        
    
    reader.endObject();
    return new Match(team1, team2, id, round, bracket, status, date, time);



public Match.Team readTeam(JsonReader reader) throws IOException 
    String teamName = null;
    int score = -1;
    boolean winner = false;

    reader.beginObject();
    while (reader.hasNext()) 
            String name = reader.nextName(); //this is where the error occurs
            switch (name) 
                case "participant":
                    if(reader.peek() != JsonToken.NULL) 
                        teamName = reader.nextString();
                    
                    else 
                        teamName = null;
                    
                    break;
                case "score":
                    if(reader.peek() != JsonToken.NULL) 
                        score = reader.nextInt();
                    
                    else 
                        score = -1;
                    
                    break;
                case "result":
                    if(reader.peek() != JsonToken.NULL) 
                        winner = reader.nextInt() == 1;
                    
                    else 
                        winner = false;
                    
                    break;
                default:
                    reader.skipValue();
                    break;
            
    
    reader.endObject();

    return new Match.Team(teamName, score, winner);

但是,当我尝试解析对手数组时,我在 readTeam() 中出现错误应为名称但为 NULL,我很困惑为什么会发生这种情况。

起初我不知道 peek() 所以在 readMatch() 方法中我使用了 try/catch,我必须改变它,但它应该与问题无关。我找不到关于这个特定错误的任何信息,有很多关于其他类似错误的主题(预期名称是 string/int/whatever)但在这里我找不到它不起作用的原因。您有任何解决方法的想法吗?

【问题讨论】:

您是否有理由不使用GSON 来解析JSON 嗯,不是真的。我仍然是 Java 的初学者和 android 的新手,这是我在解析 JSON 时看到的第一件事。以前我只是简单地使用 StringBuilder 并使用 getJSONObject(),但是因为文件太大,我的内存不足。我想我可以试试 GSON,但首先我没有太多时间,其次我很有信心我的问题很容易解决,只是找不到原因。 有空的时候看看GSON。祝你好运。 【参考方案1】:

您也应该使用null 令牌,调用nextNull()skipValue(),否则Reader 将不会前进并会坚持使用此null。例如:

case "result":
    if(reader.peek() != JsonToken.NULL) 
        winner = reader.nextInt() == 1;
     else 
        winner = false;
        reader.nextNull(); // note on this
    
    break;

https://developer.android.com/reference/android/util/JsonReader

可以使用 nextNull() 或 skipValue() 来使用 Null 字面量。

【讨论】:

【参考方案2】:

好吧,我找到了一个解决方案,就像我想象的那样,它比我想象的要简单。所以基本上当我检查空值时,就像这样:

 if(reader.peek() != JsonToken.NULL) 
   teamName = reader.nextString();
 
 else 
   teamName = null;
 

所谓的“阅读器光标”不会移动,所以它基本上停留在 teamName 的值上(在这种情况下)。所以最简单的解决方案是将reader.skipValue(); 放入else 块中。我还在我的代码中发现了另一个错误,在case "group_number" 中,我实际上将上述“光标”移动了两次,但解决方案很明显。希望它对某人有所帮助。

【讨论】:

这将教会我不要一开始就通读所有答案:)。这正是我遇到的问题。我使用了 nextNull() 而不是 skipValue(),但在我的情况下它看起来并不重要。

以上是关于JsonReader - 读取数组抛出预期名称但为 NULL的主要内容,如果未能解决你的问题,请参考以下文章

使用 JsonReader 将缓存的 Json 文件读取为 ByteArray

JsonReader 抛出 IllegalStateException

从 JsonReader 读取 JObject 时出错。当前 JsonReader 项不是对象:StartArray。小路

Spring Data JPA 'jpaMappingContext' 错误,IllegalStateException:预期能够解析类型但为空

Spark 数据集显示架构但为 show() 方法抛出 UnsupportedOperation 异常

PyTorch - RuntimeError:后端 CPU 的预期对象,但为参数 #2 'weight' 获得了后端 CUDA