前言
xml解析百度很多都是OC,我们来干一波Swift吧,群里大佬比较多,语法不会的问大佬,编译器不会的问大佬,炒股的问大佬.... 学习交流:642363427 大佬太多,不慌。
今日提示: 知耻下问,后发先至。
一、XMLParser的了解
对于接触过IOS解析XML的应该很多吧...我是写Android的我司项目会涉及到很多xml解析导出给CAD然后CAD解析完成之后进行绘制编辑等。原生Android有很多对于XML的解析方式[ SAX , Pull , DOM 等],Flutter的对于XML解析很少了之前就见过XML这个库。
- 在使用最原始的XMLParser之前,我百度看过其他人封装的解析器,在分离方面显的很麻烦。对于类的构建要求比较高,如果涉及到上千节点的的xml那就太过于麻烦。我们先来最原始基本的,说不定是最舒服的方式。在 Swift里面XMLParser 为我们开发提供了 便利 ,如下我们看看源码也就三个初始化构造函数 init(..) ,一个开始解析的方法 parse() ,一个解析器委托 delegate ,其实最主要的就是解析器委托了,所有解析的过程都交付委托给解析器委托delegate工具了。
open class XMLParser : NSObject { //url初始化也可以 public convenience init?(contentsOf url: URL) //根据文件字节bytes data初始化也可以 public init(data: Data) //stream初始化也可以 @available(iOS 5.0, *) public convenience init(stream: InputStream) //XML解析器委托 unowned(unsafe) open var delegate: XMLParserDelegate? open var shouldProcessNamespaces: Bool open var shouldReportNamespacePrefixes: Bool @available(iOS 8.0, *) open var externalEntityResolvingPolicy: XMLParser.ExternalEntityResolvingPolicy @available(iOS 8.0, *) open var allowedExternalEntityURLs: Set<URL>? open func parse() -> Bool open func abortParsing() open var parserError: Error? { get } open var shouldResolveExternalEntities: Bool }
二、新建xml文件且导入项目
1.新建.xml文件然后写入你想解析的节点或者已有的及其复杂的.xml文件。我的如下(粘贴的):
<?xml version="1.0" encoding="utf-8"?> <Users> <User id="101"> <name>航歌</name> <tel> <mobile>1234567</mobile> <home>025-8100000</home> </tel> </User> <User id="102"> <name>hangge</name> <tel> <mobile>8989889</mobile> <home>025-8122222</home> </tel> </User> </Users>
2.导入xml
三.解析xml
1.新建结构
我们根据xml的内容来新建数据模型对于数据模型是你的需求所决定的。这里也就演变出不同的解析过程对于赋值方式的不同。有些人的数据模型如下说我只想要个User其他的内部节点作为其内部属性:
//struct也行 struct MyUser{ var id: String? //编号 var name: String? //姓名 var tel:Tel?//电话 class Tel { var mobile: String? //手机 var home: String? //固话 } } //class 也行都为来储存数据。 class MyUser { var id: String? //编号 var name: String? //姓名 var tel:Tel?//电话 class Tel { var mobile: String? //手机 var home: String? //固话 } }
有些人需要分开User和Tel这是一个举例。但是在实际中我们对于父子节点来说是其类-->属性,但是可能xml作为接口文件。而当前页面只需要Tel不需要整体,解析那更简单了。
class Tel { var mobile: String? //手机 var home: String? //固话 }
2.解析器委托进行解析。
XML解析器委托:XMLParserDelegate作为代理接口协议,定义了解析过程所
【1】:节点属性解析
解析器,必须每个节点的开始和结束都需要提供接口去解析成模型,如下代码:每次到一个节点开始都会调用下面方法-->这时我们进行创建对应的数据 类class 或者 模型结构struct .
<?xml version="1.0" encoding="utf-8"?> <Users xmlns ="http://www.example.com/DEFAULT"> <User id="101" uid="2021 come on"> <name>航歌</name> <tel> <mobile>1234567</mobile> <home>025-8100000</home> </tel> </User> <User id="102"> <name>hangge</name> <tel> <mobile>8989889</mobile> <home>025-8122222</home> </tel> </User> </Users>
elementName | namespaceURI | qualifiedName | attributes |
---|---|---|---|
每个节点起始名称 | 命名空间 | 限定名称 | 属性 |
如上面:User,User,tel等有自节点,而不是字符节点如:<name>航歌</name> | 相当于身份标示命名,学过前端的都明白XML第一节课估计就是 | 本地名?百度百度:joy: | 节点属性是如上id="101"uid="2021 come on",而不是子节点 |
<elementName ><otherElementName> | xmlns ="http://www.example.com/DEFAULT" | :joy: | attributeDict["id"],attributeDict["uid"] |
// 遇到一个开始标签时调用 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { }
- 进行创建对应的数据类或者模型结构.
// 遇到一个开始标签时调用 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName //每个节点名的开始就是我们要不要实例化模型或者类。 switch elementName { case "User": //创建一个新用户对象 user = MyUser() //保存下id user.id = attributeDict["id"] case "tel": tel = MyUser.Tel() default: break } }
【2】:解析字符节点
foundCharacters |
---|
每个字符节点内容 |
<name>航歌<name> |
// 遇到字符串时调用 func parser(_ parser: XMLParser, foundCharacters string: String) { //这里只是去去空格过滤字符的。别感觉到太难了:smile: let data = string.trimmingCharacters(in: .whitespacesAndNewlines) //接下来每遇到一个字符,将该字符追加到相应的 property 中 switch currentElement{ case "name": user.name = user.name ?? "" + data case "mobile": tel.mobile = tel.mobile ?? "" + data case "home": tel.home = tel.home ?? "" + data default: break } }
import UIKit import SwiftEventBus class XMLUtils:NSObject, XMLParserDelegate{ //保存最终解析的结果 var users:[MyUser] = [] static let mself=XMLUtils() //当前元素名 var currentElement = "" //当前用户 var user:MyUser! var tel:MyUser.Tel! // 遇到一个开始标签时调用 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName switch elementName { case "User": //创建一个新用户对象 user = MyUser() //保存下id user.id = attributeDict["id"] case "tel": tel = MyUser.Tel() default: break } } // 遇到字符串时调用 func parser(_ parser: XMLParser, foundCharacters string: String) { let data = string.trimmingCharacters(in: .whitespacesAndNewlines) //接下来每遇到一个字符,将该字符追加到相应的 property 中 switch currentElement{ case "name": user.name = user.name ?? "" + data case "mobile": tel.mobile = tel.mobile ?? "" + data case "home": tel.home = tel.home ?? "" + data default: break } } // 遇到结束标签时调用 func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { //标签User结束时将该用户对象,存入数组容器。 switch elementName { case "User": users.append(user) case "tel": user.tel=tel default: break } } func parserDidEndDocument(_ parser: XMLParser) { //输出结果 for i in 0...(users.count - 1 ){ if let tel = users[i].tel { if let mobile = tel.mobile { print("User: id:\(users[i].id!),name:\(users[i].name!)," + "mobile:\(mobile)," + "home:\(tel.home)") } } } SwiftEventBus.post("personFetchEvent", sender:users[0]) } //用户对象 }
四.调用展示
// // SwiftUI_XML_View.swift // swiftUiStudy // // Created by 王飞 on 2020/12/2. // import SwiftUI import SwiftEventBus struct SwiftUI_XML_View: View{ //记录当前节点的名字 var currentNodeName:String! @State var xmlName:String! = "解析结果" var body: some View { Text("\(xmlName)").onTapGesture { let xmlUrl = URL(fileURLWithPath: Bundle.main.path(forResource: "users", ofType: "xml")!) let parser = XMLParser(contentsOf:xmlUrl) print("解析开始") //设置delegate parser?.delegate=XMLUtils.mself //开始解析 parser?.parse() SwiftEventBus.onMainThread(XMLUtils(), name:"personFetchEvent") { result in let user : MyUser = result!.object! as! MyUser print(user.name) // will output "john doe" xmlName=user.name } } } } struct SwiftUI_XML_View_Previews: PreviewProvider{ static var previews: some View { SwiftUI_XML_View() } }