CoreOffice / XMLCoder

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

XML same item with different tags decoded into same bucket #281

Open app4g opened 9 months ago

app4g commented 9 months ago

this is likely a user issue, using the wrong method or something. Pointers appreciated. This is the XML file I want to decode

<workout_file>
    <author>afaag</author>
    <name>afa</name>
    <description>ag326 wges</description>
    <sportType>bike</sportType>
    <tags>
    </tags>
    <workout>
        <Warmup Duration="600" PowerLow="0.25" PowerHigh="0.75"/>
        <Cooldown Duration="600" PowerLow="0.75" PowerHigh="0.25"/>
    </workout>
</workout_file>

This is the code which I'm currently using to decode the XML. I initially thought that the code will properly differentiate between the XMLs based on the tags etc but it seems like it's using the attributes within the tags.

Based on the Above XML, only decoding WarmUp gets printed out. If I were to move cooldown above warmup then it will print decoding cooldown for both tags

Is there something that can be done to properly decode it based on the tags? Note that I am using XMLCoder (https://github.com/CoreOffice/XMLCoder)

struct Workout: Codable {
  let workout: [WorkoutSegment]

  enum CodingKeys: String, CodingKey {
    case workout = "workout"
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    var workoutSegments = [WorkoutSegment]()
    var workoutContainer = try container.nestedUnkeyedContainer(forKey: .workout)

    while !workoutContainer.isAtEnd {

     if let warmUp = try? workoutContainer.decode(WarmUp.self) {
        print("decoding WarmUp")
        workoutSegments.append(WorkoutSegment(warmUp: warmUp))
      } else if let coolDown = try? workoutContainer.decode(CoolDown.self) {
        print("decoding CoolDown")
        workoutSegments.append(WorkoutSegment(coolDown: coolDown))
      } else {
        // If the next element cannot be decoded, exit the loop
        print("=== oops ===")
        break
      }
    }

    self.workout = workoutSegments
  }
}

struct WorkoutSegment: Codable {
  let warmUp: WarmUp?
  let coolDown: CoolDown?

  enum CodingKeys: String, CodingKey {
    case warmUp = "Warmup"
    case coolDown = "Cooldown"
  }

  init(warmUp: WarmUp? = nil, coolDown: CoolDown? = nil) {
    self.warmUp = warmUp
    self.coolDown = coolDown
  }
}

// <Warmup Duration="300" PowerLow="0.42449999" PowerHigh="0.70449996" />
struct WarmUp: Codable {
  let duration: Double
  let powerLow: Double
  let powerHigh: Double
  let textevent: [TextEvent]?

  enum CodingKeys: String, CodingKey {
    case duration = "Duration"
    case powerLow = "PowerLow"
    case powerHigh = "PowerHigh"
    case textevent = "textevent"
  }
}

struct CoolDown: Codable {
  let duration: Double
  let powerLow: Double
  let powerHigh: Double
  let textevent: [TextEvent]?

  enum CodingKeys: String, CodingKey {
    case duration = "Duration"
    case powerLow = "PowerLow"
    case powerHigh = "PowerHigh"
    case textevent = "textevent"
  }
}

Also tried this

while !workoutContainer.isAtEnd {
  if let warmUp = try? workoutContainer.decode(WarmUp.self) {
    print("decoding WarmUp")
    workoutSegments.append(WorkoutSegment(warmUp: warmUp))
  }

 if let coolDown = try? workoutContainer.decode(CoolDown.self) {
    print("decoding CoolDown")
    workoutSegments.append(WorkoutSegment(coolDown: coolDown))
  }
}

This yielded this output:

decoding WarmUp
decoding WarmUp
Successfully decoded XML file: