Android Json不规则键值解析与转换

简述

在Android开发的时候,通过网络请求获取后台返回数据与上传数据给后台是十分常见的。有时候,我们会遇到需要解析和传递特殊键值的Json,对于这种情况,引出了本次要讲诉的内容。

Json数据解析

开发的时候可能会遇到如下要解析奇葩json字段

//[]中代表报名该选修课的学生id
{"ret":0,
    "response":{
        "tag_category":{
            "选修课":{
                "红楼梦名著解析":["1","2","7","8"],
                "书法之美":["1","2","3","4","5"]
            }
            
        }
    }
}

有的小伙伴可能会想到,我们可以通过使用谷歌的Gson解析

implementation 'com.google.code.gson:gson:2.8.0'

将我们上文要解析的封装成javaBean,结果如下

public class ClassCourses {

    /**
     * ret : 0
     * response : {"tag_category":{"选修课":{"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}}}
     */

    private int ret;
    private ResponseBean response;

    public int getRet() {
        return ret;
    }

    public void setRet(int ret) {
        this.ret = ret;
    }

    public ResponseBean getResponse() {
        return response;
    }

    public void setResponse(ResponseBean response) {
        this.response = response;
    }

    public static class ResponseBean {
        /**
         * tag_category : {"选修课":{"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}}
         */

        private TagCategoryBean tag_category;

        public TagCategoryBean getTag_category() {
            return tag_category;
        }

        public void setTag_category(TagCategoryBean tag_category) {
            this.tag_category = tag_category;
        }

        public static class TagCategoryBean {
            /**
             * 选修课 : {"红楼梦名著解析":["1","2","7","8"],"书法之美":["1","2","3","4","5"]}
             */

            private 选修课Bean 选修课;

            public 选修课Bean get选修课() {
                return 选修课;
            }

            public void set选修课(选修课Bean 选修课) {
                this.选修课 = 选修课;
            }

            public static class 选修课Bean {
                private List<String> 红楼梦名著解析;
                private List<String> 书法之美;

                public List<String> get红楼梦名著解析() {
                    return 红楼梦名著解析;
                }

                public void set红楼梦名著解析(List<String> 红楼梦名著解析) {
                    this.红楼梦名著解析 = 红楼梦名著解析;
                }

                public List<String> get书法之美() {
                    return 书法之美;
                }

                public void set书法之美(List<String> 书法之美) {
                    this.书法之美 = 书法之美;
                }
            }
        }
    }
}

然后请求的时候再对应解析

public class MainActivity extends AppCompatActivity {

    private Gson gson=new GsonBuilder().create();
    private String json1="{\"ret\":0,\n" +
            "    \"response\":{\n" +
            "        \"tag_category\":{\n" +
            "            \"选修课\":{\n" +
            "                \"红楼梦名著解析\":[\"1\",\"2\",\"7\",\"8\"],\n" +
            "                \"书法之美\":[\"1\",\"2\",\"3\",\"4\",\"5\"]\n" +
            "            }\n" +
            "            \n" +
            "        }\n" +
            "    }\n" +
            "}";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ClassCourses classCourses=gson.fromJson(json1,ClassCourses.class);
        classCourses.getResponse().getTag_category().get选修课().get书法之美();
    }
}

这种做法虽然可以解析当前的,但是当后台增加了新的报名课程,如新增:西游记解读,此时,再用这个封装的类去解析,会发现解析不了。我们不可能知道什么时候会出现新的课程,这种动态新增此时是不适应上诉方法。

为此,我们可以通过JSONObject 依次取出,还是上面的数据,我们观察了下它的结构,发现我们只需要获取选修课这个列表,每个课程对应有一个选修的学生集合,我们自己设计一个SelectCoursesBean

public class SelectCoursesBean {
    private String className;
    private List<String> studentId;


    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public List<String> getStudentId() {
        return studentId;
    }

    public void setStudentId(List<String> studentId) {
        this.studentId = studentId;
    }

    @Override
    public String toString() {
        return "SelectCoursesBean{" +
                "className='" + className + '\'' +
                ", studentId=" + studentId +
                '}';
    }
}

然后在我们要解析的界面一层层取出键和值
analysisByJSONObject() 函数如下:

    private void analysisByJSONObject() {
        List<SelectCoursesBean> coursesBeanList=new ArrayList<>();
        try {
            JSONObject object=new JSONObject(json);
            JSONObject response=new JSONObject(object.get("response").toString());
            JSONObject tag_category=new JSONObject(response.get("tag_category").toString());
            JSONObject course=new JSONObject(tag_category.get("选修课").toString());
            Iterator<String> keys=course.keys();
            while (keys.hasNext()){
                String key=keys.next();//课程名

                List<String> studentId=new ArrayList<>();
                //通过JSONArray  一个个值遍历打出来
                JSONArray jsonArray=new JSONArray(course.get(key).toString());
                for(int i=0;i<jsonArray.length();i++){
                    studentId.add(jsonArray.get(i).toString());
                }
                SelectCoursesBean coursesBean=new SelectCoursesBean();
                coursesBean.setClassName(key);
                coursesBean.setStudentId(studentId);
                coursesBeanList.add(coursesBean);
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

        Log.e("TAG","数据结果:"+coursesBeanList.toString());
    }

如果觉得for循环麻烦,还是可以用Gson+JSONObject 混合着用,没有区别,思路是一样的

    private void anotherAnalysis() {
        Gson gson=new GsonBuilder().create();
        List<SelectCoursesBean> coursesBeanList=new ArrayList<>();
        try {
            JSONObject object=new JSONObject(json);
            JSONObject response=new JSONObject(object.get("response").toString());
            JSONObject tag_category=new JSONObject(response.get("tag_category").toString());
            JSONObject course=new JSONObject(tag_category.get("选修课").toString());
            Iterator<String> keys=course.keys();
            while (keys.hasNext()){
                String key=keys.next();//课程名
                String value=course.optString(key);//学生ID json
                //为了方便还可以用谷歌的,
                List<String> studentId=gson.fromJson(value,List.class);
                SelectCoursesBean coursesBean=new SelectCoursesBean();
                coursesBean.setClassName(key);
                coursesBean.setStudentId(studentId);
                coursesBeanList.add(coursesBean);
            }


        } catch (JSONException e) {
            e.printStackTrace();
        }
          Log.e("TAG","数据结果:"+coursesBeanList.toString());
    }

其中打印出来的结果如下:

数据结果:[SelectCoursesBean{className='红楼梦名著解析', studentId=[1, 2, 7, 8]}, SelectCoursesBean{className='书法之美', studentId=[1, 2, 3, 4, 5]}]
转换成Json 数据

有时候也会遇到后台要求上传回去带有特殊键值的Json,如下:

{"courses": {
  "语文": {    
   "teacher":"李老师" ,
   "minutes": 90   
  },
  "数学": {
   "teacher":"赵老师" ,
   "minutes": 120
  },
  "英语": {
   "teacher":"孙老师" ,
   "minutes": 60
  }
 }}

需要上传课程,每个老师的相关信息与授课时间,观察了下它的结构,发现一个集合里一个课程名称配对一个老师相关信息,这个和map很相似(键需唯一),因此我们写个自定义对象,设置完数据后,再转换成json。
CourseModel 模型如下

public class CourseModel {
    private Map<String,Course> courses;


    public Map<String, Course> getCourses() {
        return courses;
    }

    public void setCourses(Map<String, Course> courses) {
        this.courses = courses;
    }

    public static class Course{
        private String teacher;//教师名称
        private String minutes;//分钟

        public Course(String teacher, String minutes) {
            this.teacher = teacher;
            this.minutes = minutes;
        }

        public String getTeacher() {
            return teacher;
        }

        public void setTeacher(String teacher) {
            this.teacher = teacher;
        }

        public String getMinutes() {
            return minutes;
        }

        public void setMinutes(String minutes) {
            this.minutes = minutes;
        }

        @Override
        public String toString() {
            return "Course{" +
                    "teacher='" + teacher + '\'' +
                    ", minutes='" + minutes + '\'' +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "CourseModel{" +
                "courses=" + courses +
                '}';
    }
}

通过Gson 将对象解析成Json 数据

    private void useGsonToParseJson() {
        Gson gson=new Gson();
        CourseModel.Course course1=new CourseModel.Course("李老师","90");
        CourseModel.Course course2=new CourseModel.Course("赵老师","120");
        CourseModel.Course course3=new CourseModel.Course("孙老师","60");
        CourseModel courseModel=new CourseModel();
        Map<String, CourseModel.Course> map=new HashMap<>();
        map.put("语文",course1);
        map.put("数学",course2);
        map.put("英语",course3);
        courseModel.setCourses(map);
        Log.e("gson","上传参数:"+ gson.toJson(courseModel));

    }

打印结果如下:

E/gson: 上传参数:{"courses":{"数学":{"minutes":"120","teacher":"赵老师"},"语文":{"minutes":"90","teacher":"李老师"},"英语":{"minutes":"60","teacher":"孙老师"}}}

至此,json解析与转换的简单使用就到此为止了。开发中遇到这种情况,可以的话先与后台沟通,这边遇到的这种情况是由于其后台祖传代码,要修改已经很难。。。不得已为之。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容