返回 导航

Swift

hangge.com

Swift - 生成XML格式数据1(使用XMLParsing库)

作者:hangge | 2018-10-12 08:10
我之前写过两篇文章介绍如何解析 XML 格式的数据,有使用第三方库的、也有使用原生代码的:
下面我接着演示如何生成 XML 数据,这个同样需要借助第三方库来实现。本文先介绍 XMLParsing 这个第三方 XML 库。

一、XMLParsing 库的安装与介绍

1,基本介绍

(1)我们知道 Swift4 中引入了 Codable 协议,可以用来实现 JSON 数据的 Encode Decode。但它并没有办法解析 XML
(2)而 XMLParsing 库同样使用了 Swift4 Codable 协议,不过它在苹果的 JSONEncoder/JSONDecoder 基础上增加了 XMLEncoder XMLDecoder,从而适应 XML 标准。

2,安装配置

(1)首先到它的 GitHub 主页上将库下载到本地:

(2)解压后将 Sources 文件夹下的整个 XMLParsing 拖到我们项目中来即可。

二、基本用法

1,模型创建

首先我们创建好图书以及书籍类别的数据模型(model),注意它们要遵循 Codable 协议。
import Foundation

//包含所有的图书分类
struct Catalogs: Codable {
    var catalogs: [Catalog]
}

//具体的图书分类
struct Catalog: Codable {
    //所属类型
    var genre: Genre
    
    //该分类下的图书
    var books: [Book]
}

//具体图书
struct Book: Codable {
    var id: String
    var title: String
    var price: Double
    var publishDate: Date
}

//图书类书
enum Genre: String, Codable {
    case computer = "计算机"
    case horror = "恐怖故事"
    case sciFi = "科幻小说"
}

2,使用样例

(1)下面代码我们创建一系列的书籍数据,并使用 XMLParsing 将其转换为相应 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])
        
        //将数据转为对应的XML字符串
        let encoder = XMLEncoder()
        do {
            let data = try encoder.encode(catalogs, withRootKey: "data") //根节点标签为data
            let xml = String(data: data, encoding: .utf8)
            print(xml!)
        } catch {
            print(error)
        }
    }

    //将字符串转成日期
    func string2Date(string:String) -> Date {
        let dateFormatter = DateFormatter.init()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let date = dateFormatter.date(from: string)
        return date!
    }
}

(2)运行结果如下:

三、进阶用法

1,修改标签名

(1)默认情况下生成 XML 数据时,使用属性名作为对应的标签名。我们可以在模型中使用 CodingKeys 指定每个属性转换后使用的标签名。
import Foundation

//包含所有的图书分类
struct Catalogs: Codable {
    var catalogs: [Catalog]
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case catalogs = "catalog"
    }
}

//具体的图书分类
struct Catalog: Codable {
    //所属类型
    var genre: Genre
    
    //该分类下的图书
    var books: [Book]
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case genre
        case books = "book"
    }
}

//具体图书
struct Book: Codable {
    var id: String
    var title: String
    var price: Double
    var publishDate: Date
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case id, title, price
        case publishDate = "publish_date"
    }
}

//图书类书
enum Genre: String, Codable {
    case computer = "计算机"
    case horror = "恐怖故事"
    case sciFi = "科幻小说"
}

(2)运行结果如下:

2,日期格式化

默认情况下日期类型(Date)的属性值输出的是数字形式,我们可以使用日期格式化器将其格式化成指定日期格式。
//创建第一个图书分类数据
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])

//将数据转为对应的XML字符串
let encoder = XMLEncoder()

//设置日期格式化器
let formatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    return formatter
}()
encoder.dateEncodingStrategy = .formatted(formatter)

do {
    let data = try encoder.encode(catalogs, withRootKey: "data")
    let xml = String(data: data, encoding: .utf8)
    print(xml!)
} catch {
    print(error)
}

3,设置 XML 头声明信息(XML Header)

//将数据转为对应的XML字符串
let encoder = XMLEncoder()

do {
    let data = try encoder.encode(catalogs, withRootKey: "data",
                    header: XMLHeader(version: 1.0, encoding: "utf-8", standalone: "no"))
    let xml = String(data: data, encoding: .utf8)
    print(xml!)
} catch {
    print(error)
}

附:使用 XMLParsing 库解析 XML 数据

XMLParsing 除了可以将模型转成 XML 数据外,同样可以将 XML 数据解析成对应的模型。下面通过样例进行演示。

1,基本用法

(1)假设我们有个 xml 数据文件(books.xml),内容如下:
<data>
    <catalogs>
        <genre>计算机</genre>
        <books>
            <publishDate>558288000</publishDate>
            <title>神经网络设计</title>
            <id>101</id>
            <price>99</price>
        </books>
        <books>
            <publishDate>172425600</publishDate>
            <title>代码大全</title>
            <id>102</id>
            <price>108</price>
        </books>
    </catalogs>
    <catalogs>
        <genre>科幻小说</genre>
        <books>
            <publishDate>523987200</publishDate>
            <title>三体</title>
            <id>201</id>
            <price>70</price>
        </books>
    </catalogs>
</data>

(2)解析前我们先创建对应的数据模型(model):
import Foundation

//包含所有的图书分类
struct Catalogs: Codable {
    var catalogs: [Catalog]
}

//具体的图书分类
struct Catalog: Codable {
    //所属类型
    var genre: Genre
    
    //该分类下的图书
    var books: [Book]
}

//具体图书
struct Book: Codable {
    var id: String
    var title: String
    var price: Double
    var publishDate: Date
}

//图书类书
enum Genre: String, Codable {
    case computer = "计算机"
    case horror = "恐怖故事"
    case sciFi = "科幻小说"
}

(3)接下来读取文件并进行解析,XMLParsing 会自动将其映射成对应的模型。
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 xmlData = try! Data(contentsOf: url)

        //解析数据
        let decoder = XMLDecoder()
        let catalogs: Catalogs?
        
        do {
            //将数据解析成对应的模型
            catalogs = try decoder.decode(Catalogs.self, from: xmlData)
            //遍历输出
            for catalog in catalogs!.catalogs {
                print("--- \(catalog.genre.rawValue) ---")
                for book in catalog.books {
                    print(book.title, book.price, book.publishDate)
                }
            }
        } catch {
            print(error)
        }
    }
}

(4)运行结果如下:

2,设置映射的标签名

(1)上面的样例中我们模型里的属性是和 XML 数据中标签名一一对应的。假设 xml 数据中的标签名如下:

(2)如果模型属性名与其不一致的话,使用 CodingKeys 指定每个属性对应的标签名。
import Foundation

//包含所有的图书分类
struct Catalogs: Codable {
    var catalogs: [Catalog]
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case catalogs = "catalog"
    }
}

//具体的图书分类
struct Catalog: Codable {
    //所属类型
    var genre: Genre
    
    //该分类下的图书
    var books: [Book]
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case genre
        case books = "book"
    }
}

//具体图书
struct Book: Codable {
    var id: String
    var title: String
    var price: Double
    var publishDate: Date
    
    //指定属性对应的标签文字(不改变的话则使用属性名)
    enum CodingKeys: String, CodingKey {
        case id, title, price
        case publishDate = "publish_date"
    }
}

//图书类书
enum Genre: String, Codable {
    case computer = "计算机"
    case horror = "恐怖故事"
    case sciFi = "科幻小说"
}

3,日期格式化

(1)XML 文件中的日期可能会是各种各样的形式,比如下面这种常见的“年-月-日”形式:

(2)如果我们想要将其转换成日期属性(Date),则需设置好相关的日期格式化器即可。
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 xmlData = try! Data(contentsOf: url)

        //解析数据
        let decoder = XMLDecoder()
        let catalogs: Catalogs?
        
        //设置日期格式化器
        let formatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd"
            return formatter
        }()
        decoder.dateDecodingStrategy = .formatted(formatter)
        
        do {
            //将数据解析成对应的模型
            catalogs = try decoder.decode(Catalogs.self, from: xmlData)
            //遍历输出
            for catalog in catalogs!.catalogs {
                print("--- \(catalog.genre.rawValue) ---")
                for book in catalog.books {
                    print(book.title, book.price, book.publishDate)
                }
            }
        } catch {
            print(error)
        }
    }
}
评论

全部评论(0)

回到顶部