CoreOffice / XMLCoder

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

Array Support #139

Closed ptrkstr closed 5 years ago

ptrkstr commented 5 years ago

I'm loving XMLCoder but having a bit of difficulty understanding how to decode an array of elements. Here is an example XML

<Response>
    <Room>1001</Room>
    <Children>
        <Child>
            <Name>James</Name>
            <Age>10</Age>
        </Child>
        <Child>
            <Name>Pete</Name>
            <Age>10</Age>
        </Child>
    </Children>
</Response>

Here is how I'd expect it to be structured in Swift.

struct Response: Codable {
    let Room: Int
    let Children: [Child]
}

struct Child: Codable {
    let Name: String
    let Age: Int
}

Here is how I'm decoding it:

        let decoder = XMLDecoder()
        let response = try! decoder.decode(Response.self, from: xml)

The error printed is:

Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "Name", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "Children", intValue: nil), XMLKey(stringValue: "0", intValue: 0), XMLKey(stringValue: "0", intValue: 0), CodingKeys(stringValue: "Name", intValue: nil)], debugDescription: "No attribute or element found for key CodingKeys(stringValue: \"Name\", intValue: nil) (\"Name\").", underlyingError: nil))

Is this supported functionality of XMLCoder? I couldn't find any docs.

MaxDesiatov commented 5 years ago

Hi @patrickbdev, thanks for trying XMLCoder! This case is indeed supported, the only caveat is that you need to introduce an intermediate struct to fully reflect the tree structure of your XML. If you don't provide custom coding keys and custom encoders/decoders, the names of your properties need to directly match the names of the elements and attributes (names of the types don't matter). In your example you don't have a property with name Child, so you need to add that property to the intermediate struct:

struct Response: Codable {
    let Room: Int
    let Children: Children
}

struct Children: Codable {
  let Child: [Child]
}

struct Child: Codable {
    let Name: String
    let Age: Int
}

Does that resolve your issue?

acecilia commented 5 years ago

@patrickbdev I worked around this caveat as follows: https://github.com/MaxDesiatov/XMLCoder/issues/10#issuecomment-509390151

ptrkstr commented 5 years ago

That works perfectly, thanks @MaxDesiatov. I also discovered you had a CDCatalogue test that demonstrates this. Thank you for the time taken to reply. Also great idea @acecilia .