Swift4 中的 Codable 和 XMLParser

Posted

技术标签:

【中文标题】Swift4 中的 Codable 和 XMLParser【英文标题】:Codable and XMLParser in Swift4 【发布时间】:2018-05-20 22:47:29 【问题描述】:

使用 Swift4、ios11.1、Xcode9.1,

使用新的 Swift4 类型别名“Codable”非常适合 JSON 解码(如 here 或 here 或许多其他贡献中所述)。然而,在 XML 解析方面,我找不到任何关于这种“可编码”协议是否也可以用于 XML 解码的信息。

我尝试使用 XMLParser(可以在下面的 code-excerts 中看到)。但是我没有使用“可编码”协议来简化 XML 解析过程。我该如何使用 Codable-protocol 来简化 XML 解析??

// the Fetching of the XML-data (excert shown here with a simple dataTask) :

        let myTask = session.dataTask(with: myRequest)  (data, response, error) in

        // check for error
        guard error == nil else 
            completionHandler(nil, error!)
            return
        
        // make sure we got data in the response
        guard let responseData = data else 
            let error = XMLFetchError.objectSerialization(reason: "No data in response")
            completionHandler(nil, error)
            return
        

        // the responseData is XML !!!!!!!!!!!!!!
        let parser = XMLParser(data: responseData)
        parser.delegate = self
        parser.parse()
    
    myTask.resume()

对应的XMLParserDelegate-methods:

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) 

    self.resultTrip = elementName

    // print(elementName)
    if (self.resultTrip == "TripResult") 
        self.resultTime = ""
    



func parser(_ parser: XMLParser, foundCharacters string: String) 

    let data = string.trimmingCharacters(in: .whitespacesAndNewlines)

    if data.count != 0 

        switch self.resultTrip 
        case "TimetabledTime": self.resultTime = data
        default: break
        
    


func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) 

    if self.resultTrip == "TripResult" 

        // HERE IS THE MISSING BIT: HOW DO YOU USE A CODABLE struct ???
        var myTrip = TripResult(from: <#Decoder#>)
        myTrip.resultID = self.resultTrip

    

    print(resultTime)

结构:

struct TripResult : Codable 
    let resultId : String?
    let trip : Trip?

    enum CodingKeys: String, CodingKey 

        case resultId = "ResultId"
        case trip
    

    init(from decoder: Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        resultId = try values.decodeIfPresent(String.self, forKey: .resultId)
        trip = try Trip(from: decoder)
    

我将如何使用“可编码”结构?有没有关于如何使用 Codable 协议进行 XML 解析的好例子? 任何帮助表示赞赏!

【问题讨论】:

Foundation 中没有 XMLEncoderXMLDecoder,就像 JSON 一样。 Codable 在涉及 XML 时毫无用处。 PropertyListEncoderPropertyListDecoder可以设置格式为.xml 【参考方案1】:

目前,Apple 的 Codable 协议没有解码 XML 的方法。

虽然有很多第三方库可以解析 XML,但XMLParsing library 包含一个 XMLDecoder 和一个使用 Apple 自己的 CodableXMLEncoder > 协议,并且基于 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 的区别

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

XMLEncoder 和 JSONEncoder 的区别

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

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

【讨论】:

非常感谢 S.Moore 的超详细解释! 干得好!仅供参考,构建时有一些警告。

以上是关于Swift4 中的 Codable 和 XMLParser的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 9.3(Swift 4.1)中的 Codable '没有初始化器'

用 Codable,swift 4 解析 JSON

Swift 4 Codable - API 有时提供 Int 有时提供 String

Swift 4 Codable:将 JSON 返回字符串转换为 Int/Date/Float

Swift 4:使用 Codable `Generic parameter 'T' cannot be inferred`

如何使 UIImage 符合 Codable?