XMLCoder icon indicating copy to clipboard operation
XMLCoder copied to clipboard

XML same item with different tags decoded into same bucket

Open app4g opened this issue 1 year ago • 0 comments

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 <Warmup> <Cooldown> 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:

app4g avatar Feb 07 '24 07:02 app4g