在Swift 4中实现自定义解码器 [英] Implementing a custom Decoder in Swift 4

查看:133
本文介绍了在Swift 4中实现自定义解码器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to decode an XML document using the new Decodable protocol introduced in Swift 4, however, there doesn't seem to be an existing implementation for an XML decoder that conforms to the Decoder protocol.

我的计划是使用SWXMLHash库解析XML,然后可能会使该库中的 XMLIndexer 类扩展 Decoder 协议,以便可以使用 XMLIndexer XMLIndexer SWXMLHash.parse(xmlString)返回)。

My plan was to use the SWXMLHash library to parse the XML, then possibly make the XMLIndexer class in that library extend the Decoder protocol so that my model can be initialized with an instance of XMLIndexer (XMLIndexer is returned by SWXMLHash.parse(xmlString)).

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

My issue is that I have no clue how to implement the Decoder protocol and I can't seem to find any resources online that explain how it's done. Every resource that I've found strictly mentions the JSONDecoder class which is included with the Swift standard library and no resource I've found addresses the issue of creating your own custom decoder.

推荐答案

我还没有机会将我的代码转换为框架,但是您可以看看我的Github可以同时实现XML的自定义解码器和编码器的存储库。

I haven't had a chance to turn my code into a framework yet, but you can take a look at my Github Repository that implements both a custom decoder and encoder for XML.

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

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

The encoder and decoder resides in the XML folder of the repo. It is based on Apple's JSONEncoder and JSONDecoder with changes to fit the XML standard.

XMLDecoder和JSONDecoder之间的差异


  1. XMLDecoder.DateDecodingStrategy 有一个额外的案例,标题为 keyFormatted 。这种情况下需要给您一个CodingKey一个闭包,由您来为所提供的密钥提供正确的DateFormatter。这只是JSONDecoder的 DateDecodingStrategy 上的一种方便情况。

  2. XMLDecoder.DataDecodingStrategy 有一个额外的情况。标题为 keyFormatted 。这种情况下需要给您提供CodingKey的闭包,由您决定是否为提供的密钥提供正确的数据或nil。这只是JSONDecoder的 DataDecodingStrategy 上的一种方便情况。

  3. 如果符合Codable协议的对象具有数组,并且所解析的XML不包含数组元素,XMLDecoder将为属性分配一个空数组。这是因为XML标准指出如果XML不包含该属性,则可能意味着这些元素为零。

  1. XMLDecoder.DateDecodingStrategy has an extra case titled keyFormatted. This case takes a closure that gives you a CodingKey, and it is up to you to provide the correct DateFormatter for the provided key. This is simply a convenience case on the DateDecodingStrategy of JSONDecoder.
  2. XMLDecoder.DataDecodingStrategy has an extra case titled keyFormatted. This case takes a closure that gives you a CodingKey, and it is up to you to provide the correct data or nil for the provided key. This is simply a convenience case on the DataDecodingStrategy of JSONDecoder.
  3. If the object conforming to the Codable protocol has an array, and the XML being parsed does not contain the array element, XMLDecoder will assign an empty array to the attribute. This is because the XML standard says if the XML does not contain the attribute, that could mean that there are zero of those elements.

差异在XMLEncoder和JSONEncoder之间


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

  1. Contains an option called StringEncodingStrategy, this enum has two options, deferredToString and cdata. The deferredToString option is default and will encode strings as simple strings. If cdata is selected, all strings will be encoded as CData.

编码函数比JSONEncoder引入了两个附加参数。函数中的第一个附加参数是 RootKey 字符串,该字符串会将整个XML包裹在名为该键的元素中。此参数是必需的。第二个参数是XMLHeader,如果要在编码的xml中包含此信息,则它是一个可选参数,可以采用版本,编码策略和独立状态。

The encode function takes in two additional parameters than JSONEncoder does. The first additional parameter in the function is a RootKey string that will have the entire XML wrapped in an element named that key. This parameter is required. The second parameter is an XMLHeader, which is an optional parameter that can take the version, encoding strategy and standalone status, if you want to include this information in the encoded xml.




示例


有关示例的完整列表,请参见示例XML


Examples

For a full list of examples, see the Sample XML folder in the repository.

要解析的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"
}

XMLDecoder:

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)
}

XMLEncoder:

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中实现自定义解码器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆