Swift - 生成XML格式数据2(使用XMLMapper库)
作者:hangge | 2018-10-15 08:10
一、XMLMapper 库的安装与介绍
1,基本介绍
(1)XMLMapper 同样是一个使用 Swift 语言编写的数据模型转换框架。使用它,我们可以很方便地将模型对象(类和结构体)转换为 XML,或者根据 XML 生成对应的模型对象。
(2)XMLMapper 的使用有点类似于 ObjectMapper。只不过后者实现的是模型与 JSON 间的相互转换。
2,安装配置
(1)从 GitHub 上下载最新的代码:https://github.com/gcharita/XMLMapper
(2)将下载下来的源码包中 XMLMapper.xcodeproj 拖拽至你的工程中
(3)工程 -> General -> Embedded Binaries 项,把 iOS 版的 framework 添加进来:XMLMapper.framework
(4)最后,在需要使用 XMLMapper 的地方 import 进来就可以了
import XMLMapper
二 、基本用法
1,模型定义
(1)要实现映射,我们的模型需要实现 XMLMapper 的 XMLMappable 协议,并实现该协议里的如下方法:
var nodeName: String! { get set } init(map: XMLMap) mutating func mapping(map: XMLMap)
(2)这里我定义好图书以及书籍类别的数据模型。注意:XMLMapper 定义了一个 <- 操作符来表示成员对象与 XML 中标签名的相互映射关系。
关于特殊类型的数据转换:
(1)下面代码中,对于日期类型(Date)的数据,我们使用了 XMLDateFormatterTransform 这个内置的日期转换器来实现日期的格式化输出、输入。
(2)除了 XMLDateFormatterTransform 外,XMLMapper 还提供了许多其他常用的转换器:XMLHexColorTransform、XMLURLTransform、XMLDictionaryTransform 等等。
(3)当然我们也可以创建自己的转换器,只需实现 XMLTransformType 协议即可。
(1)下面代码中,对于日期类型(Date)的数据,我们使用了 XMLDateFormatterTransform 这个内置的日期转换器来实现日期的格式化输出、输入。
(2)除了 XMLDateFormatterTransform 外,XMLMapper 还提供了许多其他常用的转换器:XMLHexColorTransform、XMLURLTransform、XMLDictionaryTransform 等等。
(3)当然我们也可以创建自己的转换器,只需实现 XMLTransformType 协议即可。
import Foundation import XMLMapper //包含所有的图书分类 class Catalogs: XMLMappable { var nodeName: String! var catalogs: [Catalog]? init(catalogs: [Catalog]) { self.catalogs = catalogs } required init(map: XMLMap) { } func mapping(map: XMLMap) { catalogs <- map["catalogs"] } } //具体的图书分类 class Catalog: XMLMappable { var nodeName: String! //所属类型 var genre: Genre! //该分类下的图书 var books: [Book]? init(genre: Genre, books:[Book]) { self.genre = genre self.books = books } required init(map: XMLMap) { } func mapping(map: XMLMap) { genre <- map["genre"] books <- map["book"] } } //具体图书 class Book: XMLMappable { var nodeName: String! var id: String! var title: String! var price: Double! var publishDate: Date! init(id: String, title:String, price:Double, publishDate:Date) { self.id = id self.title = title self.price = price self.publishDate = publishDate } required init(map: XMLMap) { } func mapping(map: XMLMap) { //日期格式化器 let formatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter }() id <- map["id"] title <- map["title"] price <- map["price"] publishDate <- (map["publishDate"], XMLDateFormatterTransform(dateFormatter: formatter)) } } //图书类型 enum Genre: String, Codable { case computer = "计算机" case horror = "恐怖故事" case sciFi = "科幻小说" }
2,使用样例
(1)下面代码我们创建一系列的书籍数据,直接调用对象的 toXMLString() 方法即可将其转换为相应 XML 字符串。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //创建第一个图书分类数据 let book1 = Book(id: "101", title: "神经网络设计", price: 99, publishDate: string2Date(string: "2018-09-11")) let book2 = Book(id: "102", title: "代码大全", price: 108, publishDate: string2Date(string: "2006-06-20")) let book3 = Book(id: "103", title: "算法导论", price: 85, publishDate: string2Date(string: "2006-05-04")) let catalog1 = Catalog(genre: .computer, books: [book1, book2, book3]) //创建第二个图书分类数据 let book4 = Book(id: "201", title: "三体", price: 70, publishDate: string2Date(string: "2017-08-10")) let book5 = Book(id: "202", title: "海底两万里", price: 90, publishDate: string2Date(string: "2002-02-20")) let catalog2 = Catalog(genre: .sciFi, books: [book4, book5]) //所有分类数据集合 let catalogs = Catalogs(catalogs: [catalog1, catalog2]) catalogs.nodeName = "data" //设置节点名称(这个是根节点) //将数据转为对应的XML字符串 let xml = catalogs.toXMLString() print(xml!) } //将字符串转成日期 func string2Date(string:String) -> Date { let dateFormatter = DateFormatter.init() dateFormatter.dateFormat = "yyyy-MM-dd" let date = dateFormatter.date(from: string) return date! } }
(2)运行结果如下:
(3)把结果数据格式化下后,数据层级会看得比较清晰些:
三、进阶用法
1,设置 XML 属性数据
上面样例中,我们都是将模型属性映射成对应的 XML 标签。我们也可以将它们(部分、或全部)映射成标签属性。
//具体图书 class Book: XMLMappable { var nodeName: String! var id: String! var title: String! var price: Double! var publishDate: Date! init(id: String, title:String, price:Double, publishDate:Date) { self.id = id self.title = title self.price = price self.publishDate = publishDate } required init(map: XMLMap) { } func mapping(map: XMLMap) { id <- map.attributes["id"] title <- map["title"] price <- map["price"] publishDate <- map["publishDate"] } }
2,使用点(.)号分隔层级
(1)下面样例可以看到对于书籍的价格(price)和日期(publishDate)这两个属性被放在 details 这个标签节点下:
class Book: XMLMappable { var nodeName: String! var id: String! var title: String! var price: Double! var publishDate: Date! init(id: String, title:String, price:Double, publishDate:Date) { self.id = id self.title = title self.price = price self.publishDate = publishDate } required init(map: XMLMap) { } func mapping(map: XMLMap) { //日期格式化器 let formatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter }() id <- map["id"] title <- map["title"] price <- map["detail.price"] publishDate <- (map["detail.publishDate"], XMLDateFormatterTransform(dateFormatter: formatter)) } }
(2)同样对于数组类型的属性,也可以使用点号将元素放在具体的子标签下(不与其他属性放在同一层级):
//具体的图书分类 class Catalog: XMLMappable { var nodeName: String! //所属类型 var genre: Genre! //该分类下的图书 var books: [Book]? init(genre: Genre, books:[Book]) { self.genre = genre self.books = books } required init(map: XMLMap) { } func mapping(map: XMLMap) { genre <- map["genre"] books <- map["books.book"] } }
附:使用 XMLMapper 库解析XML数据
XMLMapper 除了可以将模型转成 XML 数据外,同样可以将 XML 数据解析成对应的模型。下面通过样例进行演示。
(1)假设我们有个 xml 数据文件(books.xml),内容如下:
<data> <catalogs> <genre>计算机</genre> <book> <id>101</id> <title>神经网络设计</title> <price>99.0</price> <publishDate>2018-09-11</publishDate> </book> <book> <id>102</id> <title>代码大全</title> <price>108.0</price> <publishDate>2006-06-20</publishDate> </book> </catalogs> <catalogs> <genre>科幻小说</genre> <book> <id>201</id> <title>三体</title> <price>70.0</price> <publishDate>2017-08-10</publishDate> </book> </catalogs> </data>
(2)解析前我们先创建对应的数据模型(model),这个同上面一样没有变化:
import Foundation import XMLMapper //包含所有的图书分类 class Catalogs: XMLMappable { var nodeName: String! var catalogs: [Catalog]? init(catalogs: [Catalog]) { self.catalogs = catalogs } required init(map: XMLMap) { } func mapping(map: XMLMap) { catalogs <- map["catalogs"] } } //具体的图书分类 class Catalog: XMLMappable { var nodeName: String! //所属类型 var genre: Genre! //该分类下的图书 var books: [Book]? init(genre: Genre, books:[Book]) { self.genre = genre self.books = books } required init(map: XMLMap) { } func mapping(map: XMLMap) { genre <- map["genre"] books <- map["book"] } } //具体图书 class Book: XMLMappable { var nodeName: String! var id: String! var title: String! var price: Double! var publishDate: Date! init(id: String, title:String, price:Double, publishDate:Date) { self.id = id self.title = title self.price = price self.publishDate = publishDate } required init(map: XMLMap) { } func mapping(map: XMLMap) { //日期格式化器 let formatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter }() id <- map["id"] title <- map["title"] price <- map["price"] publishDate <- (map["publishDate"], XMLDateFormatterTransform(dateFormatter: formatter)) } } //图书类书 enum Genre: String, Codable { case computer = "计算机" case horror = "恐怖故事" case sciFi = "科幻小说" }
(3)接下来读取文件并进行解析,XMLMapper 会自动将其映射成对应的模型。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //获取xml数据 let file = Bundle.main.path(forResource: "books", ofType: "xml") let url = URL(fileURLWithPath: file!) let xmlString = try! String(contentsOf: url) //将数据解析成对应的模型 let catalogs = Catalogs(XMLString: xmlString) //遍历输出 for catalog in catalogs!.catalogs! { print("--- \(catalog.genre.rawValue) ---") for book in catalog.books! { print(book.title!, book.price!, book.publishDate!) } } } }
全部评论(0)