web-dev-qa-db-ja.com

Swift4のコーディング可能およびXMLParser

Swift4、iOS11.1、Xcode9.1、

新しいSwift4 typealiase "Codable"を使用すると、JSONデコードでうまく機能します(説明 here または here または他の多くのコントリビューション))。ただし、XML解析に関しては、この「コード化可能」プロトコルをXMLデコードにも使用できるかどうかについての情報は見つかりませんでした。

私はXMLParserを使用しようとしました(以下のコードexcertsで確認できます)。しかし、XML解析プロセスを簡略化するために、「コーディング可能」プロトコルを使用できませんでした。 XML解析を単純化するには、どのようにしてCodable-protocolを正確に使用する必要がありますか?

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

「コード化可能な」構造体をどのように使用する必要がありますか? XMLparsingにCodable-protocolを使用する方法に関する素晴らしい例はありますか?助けてくれてありがとう!

10
iKK

現在、AppleのCodableプロトコルには、XMLをデコードする方法がありません。

XMLを解析するサードパーティのライブラリはたくさんありますが、 XMLParsingライブラリ にはXMLDecoderXMLEncoderはApple独自のCodableプロトコルを使用し、XML標準に適合するように変更されたAppleのJSONEncoder/JSONDecoderに基づいています。

リンク: 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
}

XMLDecoder:

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

XMLEncoder:

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というタイトルの追加のケースがあります。このケースはCodi​​ngKeyを提供するクロージャーを受け取り、提供されたキーに正しいDateFormatterを提供するのはあなた次第です。これは、JSONDecoderのDateDecodingStrategyの便利なケースです。
  2. XMLDecoder.DataDecodingStrategyには、keyFormattedというタイトルの追加のケースがあります。このケースはCodi​​ngKeyを提供するクロージャーを受け取り、提供されたキーに対して正しいデータまたはnilを提供するのはあなた次第です。これは単に、JSONDecoderのDataDecodingStrategyの便利なケースです。
  3. Codableプロトコルに準拠するオブジェクトに配列があり、解析されるXMLに配列要素が含まれていない場合、XMLDecoderは空の配列を属性に割り当てます。これは、XML標準に、XMLに属性が含まれていないと記載されているため、これらの要素がゼロであることを意味している可能性があります。

XMLEncoderとJSONEncoderの違い

  1. StringEncodingStrategyというオプションが含まれています。この列挙には、deferredToStringcdataの2つのオプションがあります。 deferredToStringオプションはデフォルトであり、文字列を単純な文字列としてエンコードします。 cdataが選択されている場合、すべての文字列はCDataとしてエンコードされます。

  2. encode関数は、JSONEncoderよりも2つの追加パラメーターを受け取ります。関数の最初の追加パラメーターはRootKey文字列で、そのキーという名前の要素でXML全体がラップされます。このパラメーターは必須です。 2番目のパラメーターはXMLHeaderです。これは、エンコードされたxmlにこの情報を含める場合に、バージョン、エンコード戦略、およびスタンドアロンステータスを取得できるオプションのパラメーターです。

16
S.Moore