Swift 5: Декодировать элементы по порядку из XML - PullRequest
0 голосов
/ 29 апреля 2019

Я хочу декодировать следующий XML с использованием библиотеки XMLCoder (которая использует Codable протокол):

<?xml version="1.0" encoding="UTF-8"?>
<container>
    <p>
        <run>
            <id>1518</id>
            <text>I am answering it again.</text>
        </run>
        <properties>
            <id>431</id>
            <title>A Word About Wake Times&#xD;</title>
        </properties>
        <br/>
        <run>
            <id>1519</id>
            <text>Hello!</text>
        </run>
    </p>
    <p>
        <run>
            <id>1520</id>
            <text>I am answering it again.</text>
        </run>
    </p>
</container>

Но что-то очень важное - это сохранить порядок элементов внутриэлемент p.Например, в первом элементе p есть run, затем properties, затем br и, наконец, еще один run.

Этого нельзя достичь с помощью базовой структуры, посколькуон попытается декодировать элементы того же типа, что и массив, и не сохранит общий порядок.Я также пытался использовать enum, но та же проблема.

Знаете ли вы, как этого добиться?

Текущий нерабочий код:

struct Container: Decodable {
    let paragraphs: [Paragraph]

    enum CodingKeys: String, CodingKey {
        case paragraphs = "p"
    }
}

struct Run: Decodable {
    let id: Int
    let text: String
}

struct Properties: Decodable {
    let id: Int
    let title: String
}

struct Break: Decodable {

}

enum Entry: Decodable {
    case run(Run)
    case properties(Properties)
    case br(Break)

    private enum CodingKeys: String, CodingKey {
        case run, properties, br
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // Here, when trying to decode the run elements:
        // DecodingError.typeMismatch: Expected to decode Dictionary<String, Any> but found SharedBox<UnkeyedBox> instead.
        if let run = try container.decodeIfPresent(Run.self, forKey: .run) {
            self = .run(run)
        }
        else if let properties = try container.decodeIfPresent(Properties.self, forKey: .properties) {
            self = .properties(properties)
        }
        else {
            self = .br(try container.decode(Break.self, forKey: .br))
        }
    }
}

struct Paragraph: Decodable {
    let entries: [Entry]

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        entries = try container.decode([Entry].self)
    }
}

do {
    let result = try XMLDecoder().decode(Container.self, from: data)
    for paragraph in result.paragraphs {
        print("Paragraph :")
        for entry in paragraph.entries {
            switch entry {
            case .run(let run):
                print("Run : \(run)")
            case .properties(let properties):
                print("Properties : \(properties)")
            case .br(let br):
                print("Break : \(br)")
            }
        }
        print("End paragraph")
    }
}
catch {
    print(error)
}

Спасибо

...