1、数据准备

<data>
    <app>
        <id>1</id>
        <name>bilibili</name>
        <version>1.0</version>
    </app>
    <app>
        <id>2</id>
        <name>weibo</name>
        <version>1.2</version>
    </app>
    <app>
        <id>3</id>
        <name>wechat</name>
        <version>2.0</version>
    </app>
        <app>
        <id>4</id>
        <name>zhihu</name>
        <version>3.3</version>
    </app>
</data>

2、PULL解析

try{
	// 初始化
	// 获取xmlpull解析器工厂
	val factory = XmlPullParserFactory.newInstance()
	// 利用工厂生成一个解析器
	val parser = factory.newPullParser()
	// 放入解析源
	parser.setInput(StringReader(xmlString))
	
	// 获取扫描到的事件类型
	// 事件类型包括:   以<id>123</id>为例
	// 开始标签 START_TAG      <id>
	// 结束标签 END_TAG        </id>
	// 内容 TEXT              123
	// 开始解析XML文档   START_DOCUMENT
	// 结束解析XML文档   END_DOCUMENT
	// etc.
	var currentType = parser.eventType
	
	// app 信息
	var appId = ""
	var appName = ""
	var appVersion = ""
	
	Log.e("tag", "解析开始")
	// 如果事件类型没有遇到文档结束这个事件,就会一直扫描下去
	while(currentType != XmlPullParser.END_DOCUMENT){
		// 思路:
		// 1、扫描到标签开始时,如果这个标签name是id、name、version
		//		则赋值给上面定义的变量
		// 2、扫描到结束标签时,这个标签的name时app时,则打印上述三个变量
		// 3、在单次while循环结束之前,currentType 要赋值下一个事件
		when(currentType){
			XmlPullParser.START_TAG ->
				when(parser.name){
					"id" -> appId = parser.nextText()
					"name" -> appName = parser.nextText()
					"version" -> appVersion = parser.nextText()
				}
			XmlPullParser.END_TAG ->
				if(parser.name == "app"){
					Log.e("tag",appId )
					Log.e("tag",appName )
					Log.e("tag",appVersion )
				}
		}
		currentType = parser.next()	
	}
}catch(e:Exception){
	e.printStackTrace()
    Log.e("tag", "解析出错:${e} ")
}
Log.e("tag", "解析完成 ")

解析结果:
在这里插入图片描述


3、SAX解析

新建ContentHandler解析类


class ContentHandler:DefaultHandler(){
	// 变量:当前节点名称
	private var nodeName :String? = null
	
	// 变量:id
	private lateinit var appId: StringBuilder
	// 变量:name
	private lateinit var appName: StringBuilder
	// 变量:version
	private lateinit var appVersion: StringBuilder


	// 开始解析文档
	override fun startDocument() {
		appId = StringBuilder()
		appName = StringBuilder()
		appVersion = StringBuilder()
	}
	
	// 开始解析节点
	override fun startElement(
        uri: String?,
        localName: String?,
        qName: String?,
        attributes: Attributes?
    ) {
    		nodeName = localName
    }
	
	// 开始解析字符串
	override fun characters(ch: CharArray?, start: Int, length: Int) {
        // 判断节点名称
        when (nodeName) {
            "id" -> {
                id.append(ch, start, length)
            }
            "version" -> {
                version.append(ch, start, length)
            }
            "name" -> {
                name.append(ch, start, length)
            }
        }
    }
	
	
	// 结束解析节点
	override fun endElement(uri: String?, localName: String?, qName: String?) {
        // 结束的是 app 节点
        // 打印出来解析结果
        if (localName == "app") {
        	Log.e("tag", "appId is ${appId.toString().trim()}")
        	Log.e("tag", "appName is ${appName.toString().trim()}")
        	Log.e("tag", "appVersion is ${appVersion.toString().trim()}")

            // 清空  不妨碍下一个app节点的解析
            id.clear()
            name.clear()
            version.clear()
        }
    }
	
	// 结束解析文档
	override fun startDocument() {

	}
}

引入解析类

try{
	// 新建解析器工厂
	val saxParserFactory = SaxParserFactory.newInstance()
	// 通过解析器工厂获得解析器对象
	val saxParser = saxParserFactory.newSaxParser()
	// 获得xmlReader
	val xmlReader = saxParser.xmlReader
	// 设置解析器中的解析类
	xmlReader.contentHandler = ContentHandler()
	// 设置解析内容
	xmlReader.parse(InputSourse(StringReader(xmlString)))
}catch(e:Exception){
	e.printStackTrace()
	Log.e("tag","解析出错 ${e}")
}

解析结果:
在这里插入图片描述


4、DOM解析

DOM解析相比之前两个解析方式,更强调树状结构,父节点和子节点之间的联系更紧密

// 获取解析工厂对象
val domParserFactory = DocumentBuilder.newInstance()
// 获取解析器对象
val domParser = domParserFactory.newDocumentBuilder()
// 设置解析数据
val domSource = domParser.parse(InputSource(StringReader(xmlString))) 
// 根据节点名称获得app节点列表
val appList = domSource.documentElement.getElementByTagName("app")
// 循环app节点列表获取子节点
for(i in 0 until appList.length){
	var name = ""
    var id = ""
    var version = ""
    // 获取其中一个app节点的所有子节点列表
    val nlist = items.item(i).childNodes
	// 循环子节点列表
	for (n in 0 until nlist.length) {
    	val node = nlist.item(n)
    	// 子节点名称为  id name version 获取其内容
        node.run {
       		when (nodeName) {
	         	"id" -> id = textContent
	      		"version" -> version = textContent
	      		"name" -> name = textContent
      		}
      	}
     }
     // 结束app节点循环  之前打印 数据
     Log.e("tag",id)
     Log.e("tag",name)
     Log.e("tag",version)
}


解析结果:
在这里插入图片描述


结语

这三种适用于xml格式数据的解析
三者都用的是工厂模式进行初始化的,

pull 设置数据源用 setInput
扫描xml数据的时候引入事件(文档开始,文档结束,节点开始,节点结束,文本)

sax 需要用解析器对象获得xmlReader 对解析类 contentHandler 和解析数据进行设置 parse

dom 设置数据源用parse,节点与节点之间的联系更加紧密

代码记住是不可能记住的,写下来吧。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。