在 Swift 4 中实现自定义解码器
Implementing a custom Decoder in Swift 4
我想使用 Swift 4 中引入的新 Decodable
协议解码 XML 文档,但是,似乎没有现成的实现XML 符合Decoder
协议的解码器。
我的计划是使用 SWXMLHash 库来解析 XML,然后可能使该库中的 XMLIndexer
class 扩展 Decoder
协议,以便我的模型可以使用 XMLIndexer
的实例进行初始化(XMLIndexer
由 SWXMLHash.parse(xmlString)
返回)。
我的问题是我不知道如何实施 Decoder
协议,而且我似乎无法在网上找到任何资源来解释它是如何完成的。我发现的每个资源都严格提到 Swift 标准库中包含的 JSONDecoder
class,我发现没有任何资源解决创建您自己的自定义解码器的问题。
我还没有机会将我的代码变成一个框架,但你可以看看我的 Github 存储库,它为 XML 实现了自定义解码器和编码器。
Link: https://github.com/ShawnMoore/XMLParsing
编码器和解码器位于存储库的 XML 文件夹中。它基于 Apple 的 JSONEncoder 和 JSONDecoder,并进行了更改以适应 XML 标准。
XML解码器和 JSONDecoder 的区别
XMLDecoder.DateDecodingStrategy
有一个名为 keyFormatted
的额外案例。这种情况采用闭包,为您提供 CodingKey,您需要为所提供的密钥提供正确的 DateFormatter。这只是 JSONDecoder 的 DateDecodingStrategy 的一个方便案例。
XMLDecoder.DataDecodingStrategy
有一个名为 keyFormatted
的额外案例。这种情况采用一个闭包,为您提供 CodingKey,您可以为提供的密钥提供正确的数据或 nil。这只是 JSONDecoder 的 DataDecodingStrategy 的一个方便案例。
- 如果符合Codable协议的对象有数组,而被解析的XML不包含数组元素,XMLDecoder会给该属性赋一个空数组。这是因为 XML 标准说如果 XML 不包含该属性,则可能意味着这些元素为零。
XMLEncoder 和 JSONEncoder 的区别
包含一个名为StringEncodingStrategy
的选项,这个枚举有两个选项,deferredToString
和cdata
。 deferredToString 选项是默认选项,会将字符串编码为简单字符串。如果选择cdata,则所有字符串将被编码为CData。
encode
函数比 JSONEncoder 多接收两个参数。该函数中的第一个附加参数是一个 RootKey 字符串,它将整个 XML 包裹在一个名为该键的元素中。此参数是必需的。第二个参数是一个XMLHeader,这是一个可选参数,可以带版本,编码策略和独立状态,如果你想在编码的xml.
中包含这些信息
例子
有关示例的完整列表,请参阅存储库中的 示例 XML 文件夹。
XML 解析:
<?xml version="1.0"?>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
Swift 结构:
struct Book: Codable {
var id: String
var author: String
var title: String
var genre: Genre
var price: Double
var publishDate: Date
var description: String
enum CodingKeys: String, CodingKey {
case id, author, title, genre, price, description
case publishDate = "publish_date"
}
}
enum Genre: String, Codable {
case computer = "Computer"
case fantasy = "Fantasy"
case romance = "Romance"
case horror = "Horror"
case sciFi = "Science Fiction"
}
XML解码器:
let data = Data(forResource: "book", withExtension: "xml") else { return nil }
let decoder = XMLDecoder()
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
decoder.dateDecodingStrategy = .formatted(formatter)
do {
let book = try decoder.decode(Book.self, from: data)
} catch {
print(error)
}
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(self, withRootKey: "book", header: XMLHeader(version: 1.0))
print(String(data: data, encoding: .utf8))
} catch {
print(error)
}
我想使用 Swift 4 中引入的新 Decodable
协议解码 XML 文档,但是,似乎没有现成的实现XML 符合Decoder
协议的解码器。
我的计划是使用 SWXMLHash 库来解析 XML,然后可能使该库中的 XMLIndexer
class 扩展 Decoder
协议,以便我的模型可以使用 XMLIndexer
的实例进行初始化(XMLIndexer
由 SWXMLHash.parse(xmlString)
返回)。
我的问题是我不知道如何实施 Decoder
协议,而且我似乎无法在网上找到任何资源来解释它是如何完成的。我发现的每个资源都严格提到 Swift 标准库中包含的 JSONDecoder
class,我发现没有任何资源解决创建您自己的自定义解码器的问题。
我还没有机会将我的代码变成一个框架,但你可以看看我的 Github 存储库,它为 XML 实现了自定义解码器和编码器。
Link: https://github.com/ShawnMoore/XMLParsing
编码器和解码器位于存储库的 XML 文件夹中。它基于 Apple 的 JSONEncoder 和 JSONDecoder,并进行了更改以适应 XML 标准。
XML解码器和 JSONDecoder 的区别
XMLDecoder.DateDecodingStrategy
有一个名为keyFormatted
的额外案例。这种情况采用闭包,为您提供 CodingKey,您需要为所提供的密钥提供正确的 DateFormatter。这只是 JSONDecoder 的 DateDecodingStrategy 的一个方便案例。XMLDecoder.DataDecodingStrategy
有一个名为keyFormatted
的额外案例。这种情况采用一个闭包,为您提供 CodingKey,您可以为提供的密钥提供正确的数据或 nil。这只是 JSONDecoder 的 DataDecodingStrategy 的一个方便案例。- 如果符合Codable协议的对象有数组,而被解析的XML不包含数组元素,XMLDecoder会给该属性赋一个空数组。这是因为 XML 标准说如果 XML 不包含该属性,则可能意味着这些元素为零。
XMLEncoder 和 JSONEncoder 的区别
包含一个名为
StringEncodingStrategy
的选项,这个枚举有两个选项,deferredToString
和cdata
。 deferredToString 选项是默认选项,会将字符串编码为简单字符串。如果选择cdata,则所有字符串将被编码为CData。
中包含这些信息encode
函数比 JSONEncoder 多接收两个参数。该函数中的第一个附加参数是一个 RootKey 字符串,它将整个 XML 包裹在一个名为该键的元素中。此参数是必需的。第二个参数是一个XMLHeader,这是一个可选参数,可以带版本,编码策略和独立状态,如果你想在编码的xml.
例子
有关示例的完整列表,请参阅存储库中的 示例 XML 文件夹。
XML 解析:
<?xml version="1.0"?>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
Swift 结构:
struct Book: Codable {
var id: String
var author: String
var title: String
var genre: Genre
var price: Double
var publishDate: Date
var description: String
enum CodingKeys: String, CodingKey {
case id, author, title, genre, price, description
case publishDate = "publish_date"
}
}
enum Genre: String, Codable {
case computer = "Computer"
case fantasy = "Fantasy"
case romance = "Romance"
case horror = "Horror"
case sciFi = "Science Fiction"
}
XML解码器:
let data = Data(forResource: "book", withExtension: "xml") else { return nil }
let decoder = XMLDecoder()
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
decoder.dateDecodingStrategy = .formatted(formatter)
do {
let book = try decoder.decode(Book.self, from: data)
} catch {
print(error)
}
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(self, withRootKey: "book", header: XMLHeader(version: 1.0))
print(String(data: data, encoding: .utf8))
} catch {
print(error)
}