Android 解析xml 文件

本文介绍了在Android开发中解析xml文件的三种常见方式:DOM解析器、SAX解析器和PULL解析器。DOM解析器将整个xml加载到内存中形成树形结构,适合小文件;SAX解析器是事件驱动,内存占用少,速度较快;PULL解析器与SAX类似但更轻便,适合Android设备,是官方推荐的选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

xml文件在各种开发中都广泛应用。Android中也不例外。作为承载数据的一个重要角色,如何读写xml成为一项十分重要的技能。
在Android中,常见的xml解析器分为DOM解析器,SAX解析器,PULL解析器。
将该xml文件放置在assets目录中。

<?xml version="1.0" encoding="utf-8"?>
<persons>
    <person id="1">
        <name>zhangsan</name>
        <age>21</age>
    </person>
    <person id="2">
        <name>lisi</name>
        <age>22</age>
    </person>
    <person id="3">
        <name>wangwu</name>
        <age>23</age>
    </person>
</persons>

实体类

data class Person(val id: Int, val name: String, val age: Int)

DOM 解析器

DOM是基于树形结构的节点和信息片段的集合,允许开发人员使用DOM API遍历xml树,检索所需结构。分析该结构通常需要加载整个文档和构造整个树形结构,然后才可检索和更新节点信息。

在DOM解析过程中,会先把整个xml读入内存中,然后构建一个驻留内存的树结构,这样就可以通过代码使用DOM接口来操作整个树结构。由于DOM在内存中以树形结构存放,因此,检索和更新的效率会更高。但是对于特别大的文档,解析和加载会消耗比较大的资源,如果xml文件比较小,使用DOM也是可行的。

DOM解析的步骤

1.首先利用DocumentBuilderFactory 创建一个DocumentBuilderFactory实例
2.利用DocumentBuilderFactory 创建一个DocumentBuilder实例
3.加载整个xml文档(Document)
4.获取文档的根节点(Element)
5.获取根节点中所有子节点列表(NodeList)
6.然后获取子节点列表中的需要读取的节点

private fun dom(context: Context, fileName: String): ArrayList<Person> {
    val persons = ArrayList<Person>()    
    var inputStream: InputStream? = null
    try {
        inputStream = context.assets.open(fileName)   

        val factory = DocumentBuilderFactory.newInstance()
        val builder = factory.newDocumentBuilder()  
        val document = builder.parse(inputStream)        
        val element = document.documentElement       
        val items = element.getElementsByTagName("person")
        for (i in 0 until items.length) {
            val personNode = items.item(i) as Element

            val id = personNode.getAttribute("id").toInt()
            val name = personNode.getElementsByTagName("name")
                .item(0).firstChild.nodeValue
            val age = personNode.getElementsByTagName("age")
                .item(0).firstChild.nodeValue.toInt()

            persons.add(Person(id, name, age))
        }
    } catch (e: IOException) {
        e.printStackTrace()
    } catch (e: ParserConfigurationException) {
        e.printStackTrace()
    } finally {
        try {
            inputStream?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return persons
}

SAX 解析器

SAX是一种基于事件的解析器,事件驱动的解析流程方式是从文档的开始解析到文档的结束。不可暂停或倒退。SAX解析器占用内存少,解析速度快。SAX解析的工作原理是对文档进行顺序扫描,当扫描到文档的开始(Document),元素(Element)的开始与结束,文档(Document)的结束。等地方时通知事件处理函数,由事件处理函数作相关的动作。然后继续扫描,直到文档的结束。

SAX解析的步骤

1.首先利用SAXParserFactory创建一个SAXParserFactory实例
2.利用SAXParserFactory.newSAXParser()返回一个SAXParser解析器
3.利用SAXParser获取一个事件源对象XMLReader 
4.实例化一个DefaultHandler对象
5.连接事件源对象XMLReader到事件处理类DefaultHandler中
6.调用XMLReader的parse方法从输入源中获取xml数据
7.通过DefaultHandler返回我们所需的数据

private fun sax(context: Context, fileName: String): ArrayList<Person> {
    val persons = ArrayList<Person>()
    var inputStream: InputStream? = null
    try {  
        inputStream = context.assets.open(fileName)

        val factory = SAXParserFactory.newInstance()     
        val parser = factory.newSAXParser()        
        val reader = parser.xmlReader        
        val handler = XMLContentHandler(persons)        
        reader.contentHandler = handler        
        reader.parse(InputSource(inputStream))
    } catch (e: IOException) {
        e.printStackTrace()
    } catch (e: SAXException) {
        e.printStackTrace()
    } finally {
        try {
            inputStream?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return persons
}
class XMLContentHandler(private val persons: ArrayList<Person>) : DefaultHandler() {
    private var id = 0
    private var name = ""
    private var age = 0

    private var tagName: String? = null

    //文档开始时调用
    override fun startDocument() {
        super.startDocument()
    }

    //读取到一个标签开始时调用
    override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
        super.startElement(uri, localName, qName, attributes)
        if ("person" == localName) {
            id = attributes.getValue("id").toInt()
        }
        tagName = localName
    }

    //读取到节点内容时调用
    override fun characters(ch: CharArray, start: Int, length: Int) {
        super.characters(ch, start, length)
        if (tagName != null) {
            val data = String(ch, start, length)
            if ("name" == tagName) {
                name = data
            } else if ("age" == tagName) {
                age = data.toInt()
            }
        }
    }

    //读取到一个标签结束时调用
    override fun endElement(uri: String, localName: String, qName: String) {
        super.endElement(uri, localName, qName)
        if ("person" == localName) {
            persons.add(Person(id, name, age))
        }
        tagName = null
    }

    //文档结束时调用
    override fun endDocument() {
        super.endDocument()
    }
}

PULL 解析器

PULL解析器的运行方式与SAX类似,它提供了相似的事件,如开始元素和结束元素事件。不同的是,PULL解析在解析过程中返回的是数字。且需要我们自己获取产生的事件,然后做相应的处理。而不像SAX由处理器触发一些事件。

PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android设备中使用。Android系统内部在解析xml时也是使用的PULL解析器。Android官方推荐开发者使用PULL解析器。

PULL解析的步骤

1 创建一个XmlPullParser 对象
2 添加文档信息进XmlPullParser解析器

3 得到节点信息

private fun pull(context: Context, fileName: String): ArrayList<Person> {
    val persons = ArrayList<Person>()
    var inputStream: InputStream? = null

    var id = 0
    var name = ""
    var age = 0

    try {
        inputStream = context.assets.open(fileName)  

        val parser = Xml.newPullParser()      
        parser.setInput(inputStream, "UTF-8")
        var evtType = parser.eventType
        while (evtType != XmlPullParser.END_DOCUMENT) {
            when (evtType) {
                XmlPullParser.START_DOCUMENT -> {
                    //文档的开始
                }
                XmlPullParser.START_TAG -> {
                    //开始标签
                    when (parser.name) {
                        "person" -> id = parser.getAttributeValue(null, "id").toInt()
                        "name" -> name = parser.nextText()
                        "age" -> age = parser.nextText().toInt()
                    }
                }
                XmlPullParser.END_TAG -> {
                    //结束标签
                    if ("person" == parser.name) {
                        persons.add(Person(id, name, age))
                    }
                }
             }
             evtType = parser.next()
        }
    } catch (e: IOException) {
        e.printStackTrace()
    } finally {
        try {
            inputStream?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return persons
}

以上三种解析xml文件的结果是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值