kotlin——xml解析
·
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,节点与节点之间的联系更加紧密
代码记住是不可能记住的,写下来吧。
所有评论(0)