注意:本文使用kotlin开发语言
一、简述Sax解析XML特点
Sax解析xml文件是基于事件的。Sax对文件进行顺序扫描,当扫描到什么内容,就会报相关类型事件,去通知调用内容处理器的相关处理方法。而我们正是在内容处理器中实现自己的逻辑处理,所以一般需要自定义内容处理器类。这个内容处理器类一般继承自Sax提供的默认处理器类DefaultHandler
。Sax解析事件类型主要有5种:
- 文档开始事件:Sax会调用内容处理器类的
startDocument()
方法; - 标签开始事件:Sax会调用内容处理器类的
startElement(uri: String?, localName: String?, qName: String?, attributes: Attributes?)
方法; - 文本事件:Sax会调用内容处理器类的
characters(ch: CharArray?, start: Int, length: Int)
方法; - 标签结束事件:Sax会调用内容处理器类的
endElement(uri: String?, localName: String?, qName: String?)
方法; - 文档结束事件:Sax会调用内容处理器类的
endDocument()
方法。
自定义内容处理器类如下:
class CustomHandler: DefaultHandler(){
override fun startDocument() {
super.startDocument()
println("--------文档解析开始-------")
}
override fun startElement(uri: String?, localName: String?, qName: String?, attributes: Attributes?) {
super.startElement(uri, localName, qName, attributes)
println("--------标签解析开始:${qName.toString()}-------")
}
override fun characters(ch: CharArray?, start: Int, length: Int) {
super.characters(ch, start, length)
if(ch!=null)
println("--------文本解析开始:${String(ch,start,length)}-------")
}
override fun endElement(uri: String?, localName: String?, qName: String?) {
super.endElement(uri, localName, qName)
println("--------标签解析结束:${qName.toString()}-------")
}
override fun endDocument() {
super.endDocument()
println("--------文档解析结束-------")
}
}
Sax解析xml的方式和Dom解析xml方式不同,Sax解析xml是读入一点,处理一点,Sax解析是无状态的。所以在自定义内容处理器处理xml时,我们需要自己定义状态,也就是说Sax当前解析到哪个标签了,我们需要自己去保存并处理。带来的好处是,Sax解析xml时,占用内存小,解析速度快。带来的麻烦就是,我们需要自己多写代码,处理解析的情况。
二、实例
解析如下persons.xml
<?xml version="1.0" encoding="utf-8" ?>
<persons>
<person id="p1">
<name>小明</name>
<age>18</age>
</person>
<person id="p2">
<name>小华</name>
<age>23</age>
</person>
</persons>
自定义内容处理器类SaxParseXmlHandler
import android.text.TextUtils
import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
class SaxParseXmlHandler(): DefaultHandler(){
private lateinit var personList:ArrayList<Person>
private lateinit var rootNodeName:String
private var currentTag:String?=null
private var person:Person?=null
constructor(rootNodeName:String):this(){
this.rootNodeName = rootNodeName
this.currentTag = rootNodeName
personList = ArrayList<Person>()
}
override fun startDocument() {
super.startDocument()
}
override fun startElement(uri: String?, localName: String?, qName: String?, attributes: Attributes?) {
super.startElement(uri, localName, qName, attributes)
if(!TextUtils.isEmpty(qName)){
this.currentTag = qName.toString()
if(!TextUtils.equals(this.currentTag,this.rootNodeName)){
if(TextUtils.equals(this.currentTag,"person")){
person = Person(null,null,null)
if(attributes!=null){
person?.id = attributes.getValue(0)
}
}
}
}
}
override fun characters(ch: CharArray?, start: Int, length: Int) {
super.characters(ch, start, length)
if(ch!=null && !TextUtils.isEmpty(String(ch, start, length).trim())) {
when (this.currentTag) {
"name" -> person?.name = String(ch, start, length).trim()
"age" -> person?.age = String(ch, start, length).trim()
else -> null
}
}
}
override fun endElement(uri: String?, localName: String?, qName: String?) {
super.endElement(uri, localName, qName)
if(!TextUtils.isEmpty(qName)){
if(!TextUtils.equals(qName,this.rootNodeName)){
if(TextUtils.equals(qName,"person")){
this.personList.add(this.person as Person)
this.currentTag = null
this.person = null
}
}
}
}
override fun endDocument() {
super.endDocument()
}
fun getPersonList():ArrayList<Person>{
return this.personList
}
}
进行xml解析处理测试
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import com.mapc.demo.R
import javax.xml.parsers.SAXParserFactory
class SaxParseXmlActivity : AppCompatActivity() {
private lateinit var tvSaxParseXml:TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sax_parse_xml)
this.title = "解析XML/Sax解析XML"
var parser = SAXParserFactory.newInstance().newSAXParser()
val inputStream= assets.open("persons.xml")
val handler = SaxParseXmlHandler("persons")
parser.parse(inputStream,handler)
val list = handler.getPersonList()
if(list!=null && list.size>0) {
val sb= StringBuilder()
for ((index,item) in list.withIndex()) {
sb.append("第${index+1}个人员信息:${item.name},${item.id},${item.age}岁\n\n")
}
tvSaxParseXml = findViewById(R.id.tv_sax_parse_xml_result)
tvSaxParseXml.text = sb.toString()
}
}
}
解析结果
[完整demo]
参考资料:
2、SAX解析
3、老罗安卓开发(地址已失效,可看Android使用SAX解析XML)