【问题标题】:Parsing nested JSON objects without keys using Gson使用 Gson 解析没有键的嵌套 JSON 对象
【发布时间】:2013-09-27 18:06:13
【问题描述】:

我有一个包含以下内容的 JSON:

[ {
    "lines" : {
        "0" : "Hammersmith & City",
        "1" : "Circle"
    },
    "id" : "233",
    "name" : "Shepherd's Bush Market"
}, {
    "lines" :"",
    "id" : "233",
    "name" : "Shepherd's Bush Market"
}, {
    "lines" : {
        "0" : "Hammersmith & City",
        "1" : "Circle"
    },
    "id" : "233",
    "name" : "Shepherd's Bush Market"
},
, {
    "lines" : "",
    "id" : "233",
    "name" : "Shepherd's Bush Market"
  }]

通常,我可以创建这样的对象

public class MyObject {

    public String id;  
    public String name;
    public Line[] lines;

    public class Line {
        public String key;
        public String value;
    }
}

Gson 序列化程序会处理解析,但在这种情况下,lines 没有任何键/ID。我曾尝试使用HashMapsMaps 而不是内部类,但它不起作用。有没有办法可以使用 Gson 解析它?

更新:

我已将 linesMyObject 更改为 Map<String, String> 并在 JSON 响应中添加了更多行

目前这是我用来解析 JSON 的代码

Type listType = new TypeToken<List<MyObject>>(){}.getType();
List<MyObject> data = getGson().fromJson(str, listType);

Caused by: com.google.gson.JsonParseException: The JsonDeserializer MapTypeAdapter    failed to deserialize json object "" given the type java.util.Map<java.lang.String, java.lang.String>

查看整个 JSON 响应后,似乎lines 在不可用时返回为空的String (""),而在可用时返回为映射。我认为这可能是问题的一部分

【问题讨论】:

    标签: java android json parsing gson


    【解决方案1】:

    使用Map&lt;String, String&gt; 代替Line[] lines

    (你不需要上课Line

    它应该可以工作。

    或者,如果您的键是整数,Map&lt;Integer, String&gt; 也可以使用

    [编辑]

    您的 json 字符串表示对象列表:{..},{..},{..}

    你需要用 [] 包裹它。

    所以工作的 json 应该是:

    [
        {
            "lines": {
                "0": "Hammersmith & City",
                "1": "Circle"
            },
            "id": "233",
            "name": "Shepherd's Bush Market"
        },
        {
            "lines": {
                "0": "Hammersmith & City",
                "1": "Circle"
            },
            "id": "233",
            "name": "Shepherd's Bush Market"
        },
        {
            "lines": {
                "0": "Hammersmith & City",
                "1": "Circle"
            },
            "id": "233",
            "name": "Shepherd's Bush Market"
        }
    ]
    

    我的对象

    public class MyObject {
     public String id;
    
     public String name;
    
     public Map<String,String> lines;   
    }
    

    主要方法

        Gson gson = new Gson();
        Type type = new TypeToken<List<MyObject>>(){}.getType();
        List<MyObject > objList = gson.fromJson(str, type);
    
    
        assert(objList != null);  // validate not null
    
        for(MyObject obj : objList){
    
            System.out.println("id=" + obj.id + "; name=" + obj.name);
        }
    

    输出:

    id=233; name=Shepherd's Bush Market
    id=233; name=Shepherd's Bush Market
    id=233; name=Shepherd's Bush Market
    

    在循环中你也可以提取Map

    【讨论】:

    • 我试过这样 public Map 行;但我的应用程序崩溃并给出以下异常 09-27 19:31:38.636: E/AndroidRuntime(17729): Caused by: com.google.gson.JsonParseException: The JsonDeserializer MapTypeAdapter failed to deserialize json object "" given type java. util.Map
    • 在提取 lines 之前验证 ots 不为空且大小 > 0。很容易抓住它
    • 是的,我也在做同样的事情,我似乎找到了问题所在。有时,如果行没有值,则将其作为字符串“”返回,而当有值时,则将其作为地图对象返回
    【解决方案2】:

    我喜欢 Maxim 的简单解决方案,并为他 +1。 Bur 还有其他更复杂的方法。在Lines 类中,您可以将键写为_0_1

    class Lines {
        private String _0;
        private String _1;
        //@Override
        //public String toString() {
        //    return "Lines [0=" + _0 + ", 1=" + _1 + "]";
        //}
    
    }
    

    并在MyObject 中使用它

    class MyObject {
    
        private Lines lines;
        private String id;
        private String name;
    
        //@Override
        //public String toString() {
        //    return "Example [lines=" + lines + ", id=" + id + ", name=" + name + "]";
        //}
    }
    

    之后,您将必须创建 FieldNamingStrategy 以从数字键中删除 _

    class MyNameStrategy implements FieldNamingStrategy {
    
        static Pattern numericPattern = Pattern.compile("_\\d+");
    
        @Override
        public String translateName(Field f) {
            if (numericPattern.matcher(f.getName()).matches()){
                return f.getName().substring(1);
            }else{
                return f.getName();
            }
        }
    }
    

    要使用此策略,您需要通过GsonBuilder 创建Gson

    Gson gson = new GsonBuilder().setFieldNamingStrategy(
            new MyNameStrategy()).create();
    //...
    MyObject[] arr = gson.fromJson(jsonString, MyObject[].class);
    System.out.println(Arrays.toString(arr));
    

    您的 JSon 在"lines" : "" 中存在问题也是对的。由于您将object{...} 中的数据)放置在那里,因此您以后无法将格式更改为string(这不是 JSON 格式的对象)。
    因此,如果您可以更改您的 JSON,您应该将 "lines" : "" 替换为任一

    • "lines" : null
    • "lines" : {}

    【讨论】:

    • 我不太了解这个策略,数字 0、1 等不是键,因此它们可以继续到 20。当为此返回的值为 "" 时,似乎会发生崩溃
    • @user2611073 你能展示你用来解析你的json的代码吗?还发布了json字符串只是json数组的片段吗?如果不是,那么您可能需要用[] 包围您的json 字符串,因为(如果我没记错的话)解析json 字符串必须是一个对象或对象数组。
    • @user2611073 我用其他信息更新了我的答案,并稍微更改了之前的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多