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

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

XMLIndexer+Decoder.swift

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

推荐答案

我还没有机会将代码转换成框架,但您可以看看我的Github存储库,它实现了XML的自定义解码器和编码器.

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

编码器和解码器位于repo的XML文件夹中.它基于苹果的JSONECODER和JSONDecoder,并根据XML标准进行了修改.


Differences between XMLDecoder and JSONDecoder

  1. XMLDecoder.DateDecodingStrategy有一个名为keyFormatted的额外箱子.本例采用一个闭包,该闭包为您提供一个CodingKey,您需要为所提供的key提供正确的DateFormatter.这只是JSONDecoder DateDecodingStrategy上的一个方便 case .
  2. XMLDecoder.DataDecodingStrategy有一个名为keyFormatted的额外箱子.本例采用一个闭包,该闭包为您提供一个CodingKey,由您提供正确的数据,或者为所提供的key提供nil.这只是JSONDecoder DataDecodingStrategy上的一个方便 case .
  3. 如果符合可编码协议的对象有一个数组,并且被解析的XML不包含数组元素,XMLDecoder将为属性分配一个空array.这是因为XML标准说,如果XML不包含该属性,这可能意味着这些元素中没有任何元素.

Differences between XMLEncoder and JSONEncoder

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

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


Examples

有关示例的完整列表,请参阅存储库中的Sample XML文件夹.

XML To Parse:

<?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 Structs:

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相关问答推荐

Swift Tree实现中的弱var

如何让CTFontCreateUIFontForLanguage与汉字和表情包协同工作?

SWIFT计划计时器方法在时间间隔后未被调用

在NavigationStack上设置拐角半径:SwiftUI中的无响应内容视图区

从Swift中的泛型类继承?

相互取消任务

Swift ui 转换无法按预期工作

Swift:结果的失败类型不能是协议 - Type 'any ShadowError' cannot conform to Error

为什么我在我的 Swift iOS 应用程序项目中收到 Xcode 中的错误消息无法识别的 Select 器发送到类?

从一个范围减go 多个范围

使用 swift 的 Firebase 身份验证

如何从数据中读取以空结尾的字符串?

Swift 根据总值将数组拆分为块

Swift初始化具有可变ID的重复值数组

Vapor 4,如何按外键过滤?

Swiftwhere数组扩展

将if let与逻辑或运算符一起使用

'#selector' 的参数不引用 '@objc' 方法、属性或初始化程序

如何在 SwiftUI 中以编程方式滚动列表?

Objective-C 方法与可选需求方法 Swift 冲突