在Swift 4中实现自定义解码器

时间:2017-08-20 23:45:35

标签: xml swift decoder codable swxmlhash

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

我的计划是使用SWXMLHash库来解析XML,然后可能使该库中的Decoder类扩展XMLIndexer协议,以便可以使用{{的实例初始化我的模型。 1}} {Decoder返回XMLIndexer

XMLIndexer+Decoder.swift

我的问题是我不知道如何实现XMLIndexer协议,我似乎无法在网上找到任何解释它是如何完成的资源。我发现的每一个资源都严格地提到了Swift标准库中包含的SWXMLHash.parse(xmlString)类,而我找不到任何资源可以解决创建自定义解码器的问题。

1 个答案:

答案 0 :(得分:31)

我还没有机会将我的代码转换为框架,但您可以查看我的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不包含该属性,则可能意味着这些元素中没有任何元素。
  4. XMLEncoder和JSONEncoder之间的差异

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

    2. encode函数比JSONEncoder更多地接受两个参数。函数中的第一个附加参数是 RootKey 字符串,它将整个XML包装在名为该键的元素中。此参数是必需的。第二个参数是XMLHeader,如果要在编码的xml中包含此信息,则可以使用版本,编码策略和独立状态的可选参数。

    3. 实施例

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