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

2020-12-24  本文已影响0人  隐姓埋名的猫大叔

简述

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

上一篇下一篇

猜你喜欢

热点阅读