【问题标题】:Alamofire XML request to PropertyList对 PropertyList 的 Alamofire XML 请求
【发布时间】:2018-05-20 16:16:33
【问题描述】:

我正在尝试使用示例 https://www.w3schools.com/xml/note.xml 中的 Codable 解析 XML 数据。

我的结构是

struct Note: Codable {
  var to: String?
  var from: String?
  var heading: String?
  var body: String?
}

但是,如果我提出以下请求,我会收到错误 responseSerializationFailed : ResponseSerializationFailureReason “PropertyList 由于错误而无法序列化:\n无法读取数据,因为它的格式不正确。”

let url = URL(string: "https://www.w3schools.com/xml/note.xml")
Alamofire.request(url!, method: .get, encoding: PropertyListEncoding.default).responsePropertyList { (response) in
  guard response.error == nil else {
    print(response.error!)
    exp.fulfill()
    return
  }

  print(response)

  if let data = response.data {
    print(data)
    let decoder = PropertyListDecoder()
    let note = try! decoder.decode(Note.self, from: data)
    print(note)
  }
}

您如何在 Alamofire 中使用 responsePropertyList?

【问题讨论】:

标签: swift xml alamofire codable


【解决方案1】:

目前,Apple 的 Codable 协议没有解码 XML 的方法。虽然 Plist 是 XML,但 XML 不一定是 Plist,除非它遵循某种格式。

虽然有很多第三方库,但我建议你看看XMLParsing library。该库包含一个 XMLDecoder 和一个 XMLEncoder,它们使用 Apple 自己的 Codable 协议,并且基于 Apple 的 JSONEncoder/JSONDecoder 并进行了更改以适应 XML标准。

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


W3School 要解析的 XML:

<note>
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
    <body>Don't forget me this weekend!</body>
</note>

Swift Struct 符合 Codable:

struct Note: Codable {
    var to: String
    var from: String
    var heading: String
    var body: String
}

XML解码器:

let data = Data(forResource: "note", withExtension: "xml") else { return nil }

let decoder = XMLDecoder()

do {
   let note = try decoder.decode(Note.self, from: data)
} catch {
   print(error)
}

XML编码器:

let encoder = XMLEncoder()

do {
   let data = try encoder.encode(self, withRootKey: "note")

   print(String(data: data, encoding: .utf8))
} catch {
   print(error)
}

与第三方协议相比,使用 Apple 的 Codable 协议有很多好处。举个例子,如果 Apple 决定开始支持 XML,你就不必重构了。

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


Apple 的解码器和编码器之间存在一些差异以符合 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的选项,这个枚举有两个选项,deferredToString和cdata。 deferredToString 选项是默认选项,会将字符串编码为简单字符串。如果选择cdata,所有的字符串都会被编码为CData。

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

【讨论】:

    【解决方案2】:

    PropertyList 文件虽然是 XML 格式,但需要遵循 Apple 的 PropertyList DTD:http://www.apple.com/DTDs/PropertyList-1.0.dtd

    如果您想将常规 XML 文件(不遵循 PropertyList DTD)映射到模型对象,并且不介意使用外部库,可以尝试 XMLMapper。

    此 XML 的模型应如下所示:

    class Note: XMLMappable {
        var nodeName: String!
    
        var to: String?
        var from: String?
        var heading: String?
        var body: String?
    
        required init(map: XMLMap) { }
    
        func mapping(map: XMLMap) {
            to <- map["to"]
            from <- map["from"]
            heading <- map["heading"]
            body <- map["body"]
        }
    }
    

    你可以使用XMLMapper从字符串映射它:

    let note = XMLMapper<Note>().map(XMLString: xmlString)
    

    或者,如果您安装 Requests 子规范,您可以使用 responseXMLObject(queue:keyPath:mapToObject:completionHandler:) 函数,例如:

    let url = URL(string: "https://www.w3schools.com/xml/note.xml")
    Alamofire.request(url!, method: .get, encoding: XMLEncoding.default).responseXMLObject { (response: DataResponse<Note>) in
        let note = response.result.value
        print(note?.from ?? "nil")
    }
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      • 2017-01-26
      • 2016-02-22
      相关资源
      最近更新 更多