一、解析XML
约定一个XML文件:
<apps>
<app>
<id>1</id>
<name>Google Maps</name>
<version>1.0</version>
</app>
<app>
<id>2</id>
<name>Chrome</name>
<version>2.1</version>
</app>
<app>
<id>3</id>
<name>Google Play</name>
<version>2.3</version>
</app>
</apps>
1.Pull解析方式
private fun parseXMLWithPull(xmlData: String) {
try {
// 获取XmlPullParserFactory实例
val factory = XmlPullParserFactory.newInstance()
// 得到XmlPullParser对象
val xmlPullParser = factory.newPullParser()
// 设置XML数据
xmlPullParser.setInput(StringReader(xmlData))
// 获取当前解析事件
var eventType = xmlPullParser.eventType
var id = ""
var name = ""
var version = ""
while (eventType != XmlPullParser.END_DOCUMENT) {
// 获取当前节点名(id、name、version)
val nodeName = xmlPullParser.name
when (eventType) {
// 开始解析某个节点
XmlPullParser.START_TAG -> {
when (nodeName) {
// 获取节点具体内容
"id" -> id = xmlPullParser.nextText()
"name" -> name = xmlPullParser.nextText()
"version" -> version = xmlPullParser.nextText()
}
}
// 完成解析某个节点
XmlPullParser.ENT_TAG -> {
if ("app" == nodeName) {
Log.d("MainActivity", "id is $id")
Log.d("MainActivity", "name is $name")
Log.d("MainActivity", "version is $version")
}
}
}
// 获取下一个解析事件
eventType = xmlPullParser.next()
}
} catch(e: Exception) {
e.printStackTrace()
}
}
2.SAX解析方式
SAX语法比Pull复杂一点,但是语义方面会更加清楚。
SAX解析通常会新建一个类继承自DefaultHandler,并重写父类5个方法。
class ContentHandler : DefaultHandler() {
private var nodeName = ""
private lateinit var id: StringBuilder
private lateinit var name: StringBuilder
private lateinit var version: StringBuilder
// 开始XML解析时调用
override fun startDocument() {
id = StringBuilder()
name = StringBuilder()
version = StringBuilder()
}
// 开始解析某个节点时调用
override fun startElement(uri: String, localName: String,
qName: String, attributes: Attributes) {
// 记录当前节点名
nodeName = localName
Log.d("ContentHandler", "uri is $uri")
Log.d("ContentHandler", "localName is $localName")
Log.d("ContentHandler", "qName is $qName")
Log.d("ContentHandler", "attributes is $attributes")
}
// 获取节点内容时调用
// 获取节点内容时可能会被调用多次
// 一些换行符也会当内容解析,需要载代码中做好控制
override fun characters(ch: CharArray, start: Int, length: Int) {
// 根据当前节点名判断将内容添加到哪一个StringBuilder对象中
when (nodeName) {
"id" -> id.append(ch, start, length)
"name" -> id.append(ch, start, length)
"version" -> id.append(ch, start, length)
}
}
// 完成某个节点的解析时调用
override fun endElement(uri: String, localName: String, qName: String) {
if ("app" == localName) {
// 此时id、name、version中都可能包括回车或换行符
Log.d("ContentHandler", "id is ${id.toString.trim()}")
Log.d("ContentHandler", "name is ${name.toString.trim()}")
Log.d("ContentHandler", "version is ${version.toString.trim()}")
// 最后要将StringBuilder清空,不然会影响下一次读取
id.setLength(0)
name.setLength(0)
version.setLength(0)
}
}
// 完成整个XML解析时调用
override fun endDocument(){}
}
在MainActivity中启用SAX解析:
private fun parseXMLWithSAX(xmlData: String) {
try {
val factory = SAXParserFactory.newInstance()
val xmlReader = factory.newSAXParser().getXMLReader()
val handler = ContentHandler()
// 将ContentHandler的实例设置到XMLReader中
xmlReader.contentHandler = handler
// 开始执行解析
xmlReader.parse(InputSource(StringReader(xmlData)))
} catch (e: Exception) {
e.printStackTrace()
}
}
二、解析JSON
约定一个JSON文件:
[{"id" : "5", "version" : "5.5", "name" : "Clash of Clans"},
{"id" : "6", "version" : "7.0", "name" : "Boom Beach"},
{"id" : "7", "version" : "3.5", "name" : "Clash Royale"}]
类似地,解析JSON也有很多种方法,可以使用官方提供的JSONObject,也可以使用Google的开源库GSON。另外,一些第三方的开源库如Jackson、FastJSON等也非常不错。
1.使用JSONObject
private fun parseJSONWithJSONObject(jsonData: String) {
try {
val jsonArray = JSONArray(jsonData)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val id = jsonObject.getString("id")
val name = jsonObject.getString("name")
val version = jsonObject.getString("version")
Log.d("MainActivity", "id is $id")
Log.d("MainActivity", "name is $name")
Log.d("MainActivity", "version is $version")
}
} catch(e: Exception) {
e.printStackTrace()
}
}
2.使用GSON
添加依赖,编辑app/build.gradle:
dependencies {
implementation "com.google.code.gson:gson:2.8.6"
}
GSON可以将一段JSON格式的字符串映射成一个对象,从而不需要手动编写代码进行解析了。
2.1.解析一段JSON
比如说一段JSON格式的数据如下:
{"name" : "Tom", "age" : 20}
那我们就可以定义一个Person类,并加入name和age这两个字段,然后只需要简单地调用如下代码就可以将JSON数据自动解析成一个Person对象:
val gson = Gson()
val person = gson.fromJson(jsonData, Person::class.java)
2.2.解析一段JSON数组
比如说一段JSON格式的数组数据如下:
[{"name" : "Tom", "age" : 20},
{"name" : "Jack", "age" : 25},
这时我们需要借助TypeToken将期望解析成的数据传入fromJson()方法中,如下:
val typeOf = object : TypeToken<List<Person>>() {}.type
val people = gson.fromJson<List<Person>>(jsonData, typeOf)
2.3.实际使用
首先新增一个App类:
class App(val id: String, val name: String, val version: String)
方法:
private fun parseJSONWithGSON(jsonData: String) {
val gson = Gson()
val typeOf = object : TypeToken<List<App>>() {}.type
val appList = gson.fromJson<List<App>>(jsonData, typeOf)
for (app in appList) {
Log.d("MainActivity", "id is ${app.id}")
Log.d("MainActivity", "name is ${app.name}")
Log.d("MainActivity", "version is ${app.version}")
}
}