11.3 解析XML格式数据
11.3.1 Pull 解析方式
创建一个XmlPullParserFactory的实例,借助这个实例得到XmlPullParser 对象;
调用 XmlPullParser 对象的setInt()方法将服务器返回的XML数据设置进去,然后开始解析;
通过 getEventType()方法得到当前的解析事件,在一个while循环中 不断地进行解析,当前解析事件不等于XmlPullParser.END_DOCUMENT 时 说明解析工作未完成。
调用next()方法后可以获得下一个解析事件;
**getName()**方法可以得到当前节点的名字。
nextText() 方法可以获取节点内的具体内容;
private fun parseXMLWithPull(xmlData: String){
try {
val factory = XmlPullParserFactory.newInstance()//创建一个XmlPullParserFactory的实例
val xmlPullParser = factory.newPullParser() //得到XmlPullParser 对象
xmlPullParser.setInput(StringReader(xmlData)) // XmlPullParser 对象的setInt()方法将服务器返回的XML数据设置进去
var eventType = xmlPullParser.eventType //用于判断当前节点的类型
var id= ""
var name = ""
var version = "" //三个变量用于接收数据
while (eventType !=XmlPullParser.END_DOCUMENT){
val nodeName = xmlPullParser.name
when(eventType){
//开始解析某个节点
XmlPullParser.START_TAG ->{
when(nodeName){
"id" -> id=xmlPullParser.nextText()
"name" ->name =xmlPullParser.nextText()
"version" ->version =xmlPullParser.nextText()
}
}
//完成解析某个节点
XmlPullParser.END_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()}
}
使用明文方式传入可以用书上的代码,也可以使用usesCleartextTraffic 属性 ,(我自己运行后 这两种都可以运行出正确答案)
11.3.2 SAX解析方式
要使用SAX解析,需要创建一个类用于继承自DefaultHandler,并重写父类的五个方法:
class MyHandler :DefaultHandler() {
override fun startDocument() {//在开始解析XML的时候调用
}
override fun startElement(//在开始解析某个节点的时候调用
uri: String?,
localName: String?,
qName: String?,
attributes: Attributes?
) {
}
override fun characters(ch: CharArray?, start: Int, length: Int) { //在获取节点中内容的时候调用
}
override fun endElement(uri: String?, localName: String?, qName: String?) { //完成解析某个节点时盗用
}
override fun endDocument() {//在完成整个XML解析的时候调用
}
}
调用方式:在创建的类中处理解析的具体逻辑
在使用处的调用方式:先创建一个SAXParserFactory 对象;
然后获取xmlReader 对象 ;接着讲我们编写的Holder 的实例设置到xmlReader中;
最后调用parse() 方法开始执行。
private fun parseXMLWithSAX(xmlData :String){
try {
val factory = SAXParserFactory.newInstance()
val xmlReader = factory.newSAXParser().xmlReader
val handler =ContentHandler()
//将ContentHandler 的实例设置到XMLReader中
xmlReader.contentHandler = handler
//开始执行解析
xmlReader.parse(InputSource(StringReader(xmlData)))
}catch (e:Exception){
e.printStackTrace()
}
}
//ContentHandler.kt文件
class ContentHandler :DefaultHandler() {
private var nodeName :String?=" "
private lateinit var id:StringBuilder
private lateinit var name:StringBuilder
private lateinit var version:StringBuilder
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" -> name.append(ch,start,length)
"version" -> version.append(ch,start,length)
}
}
override fun endElement(uri: String?, localName: String?, qName: String?) {
if("app"==localName){
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)
}
}
override fun endDocument() {
}
}