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)