CoreOffice / XMLCoder

Easy XML parsing using Codable protocols in Swift
https://coreoffice.github.io/XMLCoder/
MIT License
795 stars 107 forks source link

How do you decode all nodes into a list, preserving order? #215

Open NSExceptional opened 3 years ago

NSExceptional commented 3 years ago

Lets take your book example:

<book id="123">
    <id>123</id>
    <title>Cat in the Hat</title>
    <category>Kids</category>
    <category>Wildlife</category>
</book>

If we switch it around like this, so that the order of elements no longer follows your set schema:

<book id="123">
    <id>123</id>
    <category>Kids</category>
    <title>Cat in the Hat</title>
    <category>Wildlife</category>
</book>

… we would have to decode it like so:

struct Book: Codable, ... {
    let elements: [Element]

    enum Element {
        case id(String) // string for simplicity's sake
        case title(String)
        case category(String)
    }

    enum CodingKeys: String, CodingKey {
        case id
        case title
        case category
    }
}

I don't see a way to possibly decode this by hand. If you iterate over the container's keys and try to decode them, you will get stuck at the first category (Kids) which will be decoded twice, and never decode the second one. Same for any other keys that are duplicated. I even tried making the CodingKeys a class to give them some sort of inherent identity and that didn't work. Sample init:

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

    for key in container.allKeys {
        let item = try container.decode(String.self, forKey: key)

        switch key.stringValue {
            case .id:
                elements.append(.id(item))
            case title:
                elements.append(.title(item))
            case category:
                elements.append(.category(item))
        }
    }
}

So far, I am not inclined to think this is the fault of this library. This seems more like a limitation of Codable to me, unless this is something you know how to address right away.

owenzhao commented 3 years ago

The sample is

struct Book: Codable, Equatable, DynamicNodeEncoding { let id: UInt let title: String let categories: [Category] }

And yours are

let elements: [Element]

So in you code the category should be [[String]], and the enum couldn't do that.

That's my opinion, I didn't test it with code. You should give it a try.

NSExceptional commented 3 years ago

I'm not sure you understood my example, but I'm not sure how to make it more clear. I'm not sure how you interpreted it, I don't understand what you're trying to say.

That said, I would like to preserve type information, so I don't want everything to be String

owenzhao commented 3 years ago

I see. You are requesting a new feature instead of reporting a new issue. I thought you wanted to fixed your code. But you were not. In this way, I will quit this discussion as I think the liability is on your side.

NSExceptional commented 3 years ago

That's a really interesting and harsh response. I didn't know I was asking for a feature request when I opened the issue.

I'll take that to mean "what you're asking for is not possible due to limitations of the Codable APIs," though, which would indeed make this a feature request if we assume that is the case, I guess.

NSExceptional commented 3 years ago

For anyone else reading, I would like to clarify with a better example:

<body>
    <p>hello</p>
    <em>spicy</em>
    <h1>taco</h1>
    <p>goodbye</p>
    <p>friends</p>
</body>

Assuming these tags won't contain other tags, is it possible to decode these, retaining order and type information? I don't know how to do this with this framework. @MaxDesiatov maybe you know the answer to this?