Android基础总结(12)——XML和JSON解析
时间:2022-04-29
本文章向大家介绍Android基础总结(12)——XML和JSON解析,主要内容包括XML和JSON解析、2、XML和JSON的优缺点、3、XML和JSON的解析、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
XML和JSON解析
在网络上传输数据时最常用的格式有两种:XML和JSON。本文主要就是学习如何对这两种常用的数据格式进行解析。
1、XML和JSON的定义
- XML:扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
1 <apps>
2 <app>
3 <id>1</id>
4 <name>matlab</name>
5 <version>12.5</version>
6 </app>
7 <app>
8 <id>2</id>
9 <name>chorme</name>
10 <version>9.986</version>
11 </app>
12 <app>
13 <id>3</id>
14 <name>Google Maps</name>
15 <version>10.4</version>
16 </app>
17 </apps>
- JSON:JavaScript Object Notation,一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式,同时也具备类似于C语言的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)体系的行为。这些特性使JSON成为理想的数据交换语言。JSON基于JavaScript Programming Language , Standard ECMA-262 3rd Edition - December 1999 的一个子集。 JSON就是一串字符串,只不过元素会使用特定的符号标注。 {} 双括号表示对象 [] 中括号表示数组 "" 双引号内是属性或值 : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
1 [{"id":"1","name":"matlab","version","12.5"}
2 {"id":"2","name":"chorme","version","9.986"}
3 {"id":"3","name":"Google Maps","version","10.4"}]
2、XML和JSON的优缺点
- XML的优缺点
- XML的优点
- 格式统一,符合标准;
- 容易与其他系统进行远程交互,数据共享比较方便。
-
- XML的缺点
- XML文件庞大,文件格式复杂,传输占带宽;
- 服务器端和客户端解析XML花费较多的资源和时间。
- 服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
- 客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
-
两者对比:
- 相同点:
- 两者的数据可读性基本相同
- 两者拥有同样丰富的解析手段
- 异同点:
- json的数据体积更小
- json与JS的交互更加方便
- json的解析速度更快
- xml对数据的描述性更好
3、XML和JSON的解析
我们先整体上列一个思路,对于这两种数据格式的解析,每一种数据都有多种解析方法,本文对每一种数据都提供两种经常用到的两种方式:
-
XML格式解析:Pull解析方式、SAX解析方式、DOM解析方式
- Pull解析方式:Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。
1 private void parseXMLWithPull(String xmlData){
2 try {
3 //创建一个xml解析的工厂
4 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
5 //获得xml解析类的引用
6 XmlPullParser xmlPullParser = factory.newPullParser();
7 //以流的方式传入需要解析的xml数据
8 xmlPullParser.setInput(new StringReader(xmlData));
9 //获得事件的类型
10 int eventType = xmlPullParser.getEventType();
11 String id = "" ;
12 String name = "" ;
13 String version = "" ;
14 //判断是否到了文档结束位置
15 while(eventType != XmlPullParser.END_DOCUMENT){
16 String nodeName = xmlPullParser.getName() ;
17 switch(eventType){
18
19 //遇到标签元素
20 case XmlPullParser.START_TAG:
21 if("id".equals(nodeName)){
22 //取出属性值,0是代表第0个属性
23 id = xmlPullParser.nextText();
24 } else if("name".equals(nodeName)){
25 //获取该节点的内容
26 name = xmlPullParser.nextText();
27 }else if("version".equals(nodeName)){
28 //获取该节点的内容
29 version = xmlPullParser.nextText();
30 }
31 break;
32 //标签结束
33 case XmlPullParser.END_TAG:
34 if("app".equals(xmlPullParser.getName())){
35 //这里可以做一些初始化,或者log记录
36 Log.d("MainAvtivity", "id is" + id) ;
37 Log.d("MainAvtivity", "name is" + name) ;
38 Log.d("MainAvtivity", "version is" + version) ;
39 }
40 break;
41 default:
42 break ;
43 }
44 //循环
45 eventType = xmlPullParser.next();
46 }
47 } catch (Exception e) {
48 // TODO Auto-generated catch block
49 e.printStackTrace();
50 }
51 }
1 private void parseXMLWithSAX(String xmlData){
2 try {
3 //第一步:新建一个工厂类SAXParserFactory,并获取其实例
4 SAXParserFactory factory = SAXParserFactory.newInstance();
5 //第二步:让工厂类产生一个SAX的解析类SAXParser的对象
6 SAXParser parser = factory.newSAXParser();
7 //第三步:从SAXPsrser中得到一个XMLReader实例
8 XMLReader xmlReader = parser.getXMLReader();
9 //第四步:把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler
10 MySaxHandler handler = new MySaxHandler() ;
11 xmlReader.setContentHandler(handler);
12 //第五步:将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始
13 xmlReader.parse(new InputSource(new StringReader(xmlData)));
14 } catch (Exception e) {
15 // TODO Auto-generated catch block
16 e.printStackTrace();
17 }
18 }
最重要、最关键的就是第四步,handler的实现。下面是其实现的代码:
1 /*
2 * 实现一个ContentHandler一般要一下几个步骤:
3 *
4 * 1、声明一个类,继承DefaultHandler。DefaultHandler是一个基类,这个类里面简单实现了
5 * 一个ContentHandler。我们只需要重写里面的方法即可。
6 * 2、重写 startDocument() 和 endDocument(),一般解析将正式解析之前的一些初始化工资放
7 * 到startDocument()里面,收尾的工作放到endDocument()里面。
8 * 3、重写startElement(),XML解析器遇到XML里面的tag时就会调用这个函数。经常在这个函数内是
9 * 通过localName俩进行判断而操作一些数据。
10 * 4、重写characters()方法,这是一个回调方法。解析器执行完startElement()后,解析完节点的内
11 * 容后就会执行这个方法,并且参数ch[]就是节点的内容。这个例子里我们根据currentstate的不同,来
12 * 判断当前那个tag的内容,并放到合适的实体类中。
13 * 5、重写endElement()方法,这个方法与startElement()相对应,解析完一个tag节点后,执行这个方法。
14 * 再找个例子中,如果解析一个item结束,就将RSSIiem添加到RSSFeed中。
15 *
16 */
17 class MySaxHandler extends DefaultHandler{
18
19 private String nodeName ;
20 private StringBuilder id ;
21 private StringBuilder name ;
22 private StringBuilder version ;
23
24 /**
25 * 当SAX解析器解析到XML文档开始时,会调用的方法
26 */
27 @Override
28 public void startDocument() throws SAXException {
29 id = new StringBuilder() ;
30 name = new StringBuilder() ;
31 version = new StringBuilder() ;
32 }
33
34 /**
35 * 当SAX解析器解析到XML文档结束时,会调用的方法
36 */
37 @Override
38 public void endDocument() throws SAXException {
39 super.endDocument();
40 }
41
42 /**
43 * 当SAX解析器解析到某个属性值时,会调用的方法
44 * 其中参数ch记录了这个属性值的内容
45 */
46 @Override
47 public void characters(char[] ch, int start, int length)throws SAXException {
48 //根据当前的节点名判断将内容添加到哪一个StringBuilder上
49 if("id".equals(nodeName)){
50 id.append(ch, start, length) ;
51 }else if("name".equals(nodeName)){
52 name.append(ch, start, length) ;
53 }else if("version".equals(nodeName)){
54 version.append(ch, start, length) ;
55 }
56 }
57
58 /**
59 * 当SAX解析器解析到某个元素开始时,会调用的方法
60 * 其中localName记录的是元素属性名
61 */
62 @Override
63 public void startElement(String uri, String localName, String qName,
64 Attributes attributes) throws SAXException {
65 nodeName = localName ;
66 }
67
68 /**
69 * 当SAX解析器解析到某个元素结束时,会调用的方法
70 * 其中localName记录的是元素属性名
71 */
72 @Override
73 public void endElement(String uri, String localName, String qName)
74 throws SAXException {
75 if("app".equals(localName)){
76 //这里可以做一些初始化,或者log记录
77 Log.d("MainAvtivity", "id is" + id) ;
78 Log.d("MainAvtivity", "name is" + name) ;
79 Log.d("MainAvtivity", "version is" + version) ;
80 }
81 }
82 }
-
JSON格式解析:使用JsonObject解析和使用GSON解析。可以参考:Android学习笔记45:JSON数据解析(GSON方式)
- 使用JsonObject解析:可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对(Key/Value)数值。它对外部(External:应用toString()方法输出的数值)调用的响应体现为一个标准的字符串(例如:{"JSON": "Hello, World"},最外被大括号包裹,其中的Key和Value被冒号":"分隔)。其对于内部(Internal)行为的操作格式略微,例如:初始化一个JSONObject实例,引用内部的put()方法添加数值:new JSONObject().put("JSON", "Hello, World!"),在Key和Value之间是以逗号","分隔。Value的类型包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object。
1 private void parseJSONWithJSONObject(String jsonData){
2 try {
3 JSONArray jsonArray = new JSONArray(jsonData);
4 for (int i = 0; i < jsonArray.length(); i++) {
5 JSONObject jsonObject = jsonArray.getJSONObject(i);
6 String id = jsonObject.getString("id");
7 String name = jsonObject.getString("name");
8 String version = jsonObject.getString("version");
9
10 // 解析完之后对这些数据进行处理,这里我们只是Log输出
11 Log.d("MainAvtivity", "id is" + id);
12 Log.d("MainAvtivity", "name is" + name);
13 Log.d("MainAvtivity", "version is" + version);
14 }
15 } catch (Exception e) {
16 e.printStackTrace();
17 }
18 }
1 private void parseJSONWithGson(String jsonData){
2 Gson gson= new Gson() ;
3 //我们借助TypeTolen将期望解析成的数据类型传入到fromJson()方法中
4 List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>(){}.getType()) ;
5 for(App app:appList){
6 // 解析完之后对这些数据进行处理,这里我们只是Log输出
7 Log.d("MainAvtivity", "id is" + app.getId());
8 Log.d("MainAvtivity", "name is" +app.getName());
9 Log.d("MainAvtivity", "version is" + app.getVersion());
10 }
11 }
1 /*
2 * 我们将一个JSON对象({}之间表示一个对象)封装成App类
3 */
4 class App{
5 String id ;
6 String name ;
7 String version ;
8 public String getId() {
9 return id;
10 }
11 public void setId(String id) {
12 this.id = id;
13 }
14 public String getName() {
15 return name;
16 }
17 public void setName(String name) {
18 this.name = name;
19 }
20 public String getVersion() {
21 return version;
22 }
23 public void setVersion(String version) {
24 this.version = version;
25 }
26 }
FastJSON:不详细解释。
- 【译】使用 dotnet watch 开发 ASP.NET Core 应用
- vmware安装ubuntu12.04嵌套安装xen server(实现嵌套虚拟化)
- Golang语言切片slice的线程协程安全问题
- ASP.NET Core 在 Azure 开启 HTTPS
- 算法基础:最大递减数问题(Golang实现)
- 亲身经历的痛--database/sql: Stmt的使用以及坑
- Ubuntu上通过nginx部署Django笔记
- Go学习笔记:golang交叉编译
- Python魔术方法-Magic Method
- python类中super()和__init__()的区别
- Python正则表达式:最短匹配
- 转--Go时间格式化和类型互换操作
- Python标准库(1) — itertools模块
- Linux笔记:使用Vim编辑器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- bean无法注入(与文件包位置有关)及修改包项目、model名
- Jackson第一篇
- jackson第二篇
- 从源码分析常见集合的区别之List接口
- c++ 调用ffmpeg命令获取视频属性
- Kubernetes 1.19.0——网络策略
- TypeScript 参数简化实战(进阶知识点conditional types,中高级必会)
- 最简实现Promise,支持异步链式调用(20行)
- 40行代码把Vue3的响应式集成进React做状态管理
- 写给女朋友的中级前端面试秘籍(含详细答案,15k级别)
- 写给初中级前端的高级进阶指南
- 为什么 Vue 中不要用 index 作为 key?(diff 算法详解)
- Vue3 的响应式和以前有什么区别,Proxy 无敌?
- 腾讯云TKE-PV使用cos存储案例: 容器目录权限问题
- Vue3 究竟好在哪里?(和 React Hook 的详细对比)