24. 数据解析之xml
24.1 Pull解析方式
private fun parseXMLPull(xmlData: String) {
try {
val factory = XmlPullParserFactory.newInstance()
val xmlPullParser = factory.newPullParser()
xmlPullParser.setInput(StringReader(xmlData))
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()
}
}
24.2 SAX解析方式
新建一个类继承自DefaultHandler,并重写父类的5个方法
class MySaxHandler : DefaultHandler() {
override fun startDocument() {
}
override fun startElement(
uri: String?,
localName: String?,
qName: String?,
attributes: org.xml.sax.Attributes?
) {
}
override fun characters(ch: CharArray, start: Int, length: Int) {
}
override fun endElement(uri: String, localName: String, qName: String) {
}
override fun endDocument() {
}
}
- startDocument()方法会在开始XML解析的时候调用,
- startElement()方法会在开始解析某个节点的时候调用,
- characters()方法会在获取节点中内容的时候调用,
- endElement()方法会在完成解析某个节点的时候调用,
- endDocument()方法会在完成整个XML解析的时候调用。
其中,startElement()、characters()和endElement()这3个方法是有参数的,从XML中解析出的数据就会以参数的形式传入这些方法中。需要注意的是,在获取节点中的内容时,characters()方法可能会被调用多次,一些换行符也被当作内容解析出来,我们需要针对这种情况在代码中做好控制。
class MySaxHandler : DefaultHandler() {
private var nodeName = ""
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: org.xml.sax.Attributes?
) {
// 记录当前节点名
if (localName != null) {
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() {
}
}
调用
private fun parseXMLSAX(xmlData: String) {
try {
val factory = SAXParserFactory.newInstance()
val xmlReader = factory.newSAXParser().xmlReader
val handler = MySaxHandler()
// 将ContentHandler的实例设置到XMLReader中
xmlReader.contentHandler = handler
// 开始执行解析
xmlReader.parse(InputSource(StringReader(xmlData)))
} catch (e: Exception) {
e.printStackTrace()
}
}