【XML解析】Sax解析XML

注意:本文使用kotlin开发语言


一、简述Sax解析XML特点

Sax解析xml文件是基于事件的。Sax对文件进行顺序扫描,当扫描到什么内容,就会报相关类型事件,去通知调用内容处理器的相关处理方法。而我们正是在内容处理器中实现自己的逻辑处理,所以一般需要自定义内容处理器类。这个内容处理器类一般继承自Sax提供的默认处理器类DefaultHandler。Sax解析事件类型主要有5种:

  1. 文档开始事件:Sax会调用内容处理器类的startDocument()方法;
  2. 标签开始事件:Sax会调用内容处理器类的startElement(uri: String?, localName: String?, qName: String?, attributes: Attributes?)方法;
  3. 文本事件:Sax会调用内容处理器类的characters(ch: CharArray?, start: Int, length: Int)方法;
  4. 标签结束事件:Sax会调用内容处理器类的endElement(uri: String?, localName: String?, qName: String?)方法;
  5. 文档结束事件: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]


参考资料:

1、SAX,功能强大的 API

2、SAX解析

3、老罗安卓开发(地址已失效,可看Android使用SAX解析XML)

猜你喜欢

转载自blog.csdn.net/u012995888/article/details/80211371