36

我想使用DecodableSwift 4 中引入的新协议解码 XML 文档,但是,似乎没有符合该Decoder协议的 XML 解码器的现有实现。

我的计划是使用 SWXMLHash 库来解析 XML,然后可能使该XMLIndexer库中的类扩展Decoder协议,以便我的模型可以使用XMLIndexer(XMLIndexerSWXMLHash.parse(xmlString)) 的实例初始化。

XMLIndexer+Decoder.swift

我的问题是我不知道如何实现该Decoder协议,而且我似乎无法在网上找到任何资源来解释它是如何完成的。我发现的每个资源都严格提到了JSONDecoder包含在 Swift 标准库中的类,并且我发现没有任何资源可以解决创建您自己的自定义解码器的问题。

4

1 回答 1

40

我还没有机会将我的代码变成一个框架,但是你可以看看我的 Github 存储库,它为 XML 实现了自定义解码器和编码器。

链接:https ://github.com/ShawnMoore/XMLParsing

编码器和解码器位于 repo 的 XML 文件夹中。它基于 Apple 的 JSONEncoder 和 JSONDecoder 并进行了更改以适应 XML 标准。


XMLDecoder 和 JSONDecoder 的区别

  1. XMLDecoder.DateDecodingStrategy有一个名为keyFormatted. 这种情况下需要一个为您提供 CodingKey 的闭包,您可以为所提供的密钥提供正确的 DateFormatter。这只是JSONDecoder的 DateDecodingStrategy 的一个便利案例。
  2. XMLDecoder.DataDecodingStrategy有一个名为keyFormatted. 这种情况下需要一个为您提供 CodingKey 的闭包,您可以为所提供的密钥提供正确的数据或 nil。这只是JSONDecoder的 DataDecodingStrategy 的一个方便案例。
  3. 如果符合 Codable 协议的对象有一个数组,并且正在解析的 XML 中不包含该数组元素,则 XMLDecoder 会为该属性分配一个空数组。这是因为 XML 标准规定如果 XML 不包含该属性,则可能意味着这些元素中的零个。

XMLEncoder 和 JSONEncoder 的区别

  1. 包含一个名为 的选项StringEncodingStrategy,这个枚举有两个选项,deferredToStringcdata. deferredToString选项是默认选项,会将字符串编码为简单字符串。如果选择了cdata,所有字符串都将被编码为 CData。

  2. encode与 JSONEncoder 相比,该函数接受两个额外的参数。该函数中的第一个附加参数是一个RootKey字符串,它将整个 XML 包装在一个名为该键的元素中。此参数是必需的。第二个参数是一个XMLHeader,它是一个可选参数,可以带版本、编码策略和独立状态,如果你想在编码的xml中包含这些信息。


例子

有关示例的完整列表,请参阅存储库中的Sample 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>

快速结构:

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)
}
于 2018-01-11T17:14:37.637 回答