当前位置: > > > Swift - 生成XML格式数据2(使用XMLMapper库)

Swift - 生成XML格式数据2(使用XMLMapper库)

一、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 还提供了许多其他常用的转换器:XMLHexColorTransformXMLURLTransformXMLDictionaryTransform 等等。
(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!)
            }
        }
    }
}

(4)运行结果如下:
评论0