@@ -76,21 +76,12 @@ export const xmlService = {
7676 if ( index === 0 ) ramp = 'Warmup' ;
7777 if ( index === bars . length - 1 ) ramp = 'Cooldown' ;
7878
79- if ( bar . startPower < bar . endPower ) {
80- segment = Builder . create ( ramp )
81- . att ( 'Duration' , durationType === 'time' ? bar . time : bar . length )
82- . att ( 'PowerLow' , bar . startPower )
83- . att ( 'PowerHigh' , bar . endPower )
84- . att ( 'pace' , bar . pace ) ;
85- bar . cadence !== 0 && segment . att ( 'Cadence' , bar . cadence ) ;
86- } else {
87- segment = Builder . create ( ramp )
88- . att ( 'Duration' , durationType === 'time' ? bar . time : bar . length )
89- . att ( 'PowerLow' , bar . endPower )
90- . att ( 'PowerHigh' , bar . startPower )
91- . att ( 'pace' , bar . pace ) ;
92- bar . cadence !== 0 && segment . att ( 'Cadence' , bar . cadence ) ;
93- }
79+ segment = Builder . create ( ramp )
80+ . att ( 'Duration' , durationType === 'time' ? bar . time : bar . length )
81+ . att ( 'PowerLow' , bar . startPower )
82+ . att ( 'PowerHigh' , bar . endPower )
83+ . att ( 'pace' , bar . pace ) ;
84+ bar . cadence !== 0 && segment . att ( 'Cadence' , bar . cadence ) ;
9485 } else if ( bar . type === 'interval' ) {
9586 segment = Builder . create ( 'IntervalsT' )
9687 . att ( 'Repeat' , bar . repeat )
@@ -163,31 +154,37 @@ export const xmlService = {
163154 try {
164155 const content = event . target ?. result as string ;
165156 const result = JSON . parse (
166- Converter . xml2json ( content , { compact : true , spaces : 4 } )
157+ Converter . xml2json ( content , { compact : false , spaces : 4 } )
167158 ) ;
168159
169- const workout_file = result . workout_file ;
170-
171- if ( ! workout_file ) {
160+ const workoutFileElement = result . elements ?. [ 0 ] ;
161+ if ( ! workoutFileElement || workoutFileElement . name !== 'workout_file' ) {
172162 throw new Error ( 'Invalid workout file format: missing workout_file element' ) ;
173163 }
174164
175- const name = workout_file . name ?. _text || '' ;
176- const description = workout_file . description ?. _text || '' ;
177- const author = workout_file . author ?. _text || '' ;
178- const sportType =
179- ( workout_file . sportType ?. _text as SportType ) || 'bike' ;
180- const durationType =
181- ( workout_file . durationType ?. _text as DurationType ) || 'time' ;
165+ // Helper to extract text from elements
166+ const getElementText = ( elements : any [ ] , elementName : string ) : string => {
167+ const element = elements ?. find ( ( e : any ) => e . name === elementName ) ;
168+ return element ?. elements ?. [ 0 ] ?. text || '' ;
169+ } ;
170+
171+ // Helper to get elements by name
172+ const getElementsByName = ( elements : any [ ] , elementName : string ) => {
173+ return elements ?. filter ( ( e : any ) => e . name === elementName ) || [ ] ;
174+ } ;
175+
176+ const name = getElementText ( workoutFileElement . elements , 'name' ) ;
177+ const description = getElementText ( workoutFileElement . elements , 'description' ) ;
178+ const author = getElementText ( workoutFileElement . elements , 'author' ) ;
179+ const sportType = ( getElementText ( workoutFileElement . elements , 'sportType' ) || 'bike' ) as SportType ;
180+ const durationType = ( getElementText ( workoutFileElement . elements , 'durationType' ) || 'time' ) as DurationType ;
182181
183182 const tags : string [ ] = [ ] ;
184- if ( workout_file . tags ?. tag ) {
185- const tagsArray = Array . isArray ( workout_file . tags . tag )
186- ? workout_file . tags . tag
187- : [ workout_file . tags . tag ] ;
188- tagsArray . forEach ( ( tag : any ) => {
189- if ( tag . _attributes ?. name ) {
190- tags . push ( tag . _attributes . name ) ;
183+ const tagsElement = workoutFileElement . elements ?. find ( ( e : any ) => e . name === 'tags' ) ;
184+ if ( tagsElement ?. elements ) {
185+ tagsElement . elements . forEach ( ( tagElement : any ) => {
186+ if ( tagElement . name === 'tag' && tagElement . attributes ?. name ) {
187+ tags . push ( tagElement . attributes . name ) ;
191188 }
192189 } ) ;
193190 }
@@ -198,129 +195,128 @@ export const xmlService = {
198195 let totalTime = 0 ;
199196 let totalLength = 0 ;
200197
201- const workout = workout_file . workout ;
202- const workoutElements = Object . keys ( workout ) . filter (
203- ( key ) => ! key . startsWith ( '_' )
204- ) ;
205-
206- workoutElements . forEach ( ( elementType ) => {
207- const elements = Array . isArray ( workout [ elementType ] )
208- ? workout [ elementType ]
209- : [ workout [ elementType ] ] ;
210-
211- elements . forEach ( ( element : any ) => {
212- const attr = element . _attributes ;
213-
214- if ( ! attr ) return ;
198+ const workoutElement = workoutFileElement . elements ?. find ( ( e : any ) => e . name === ' workout' ) ;
199+ if ( ! workoutElement ?. elements ) {
200+ resolve ( {
201+ name ,
202+ description ,
203+ author ,
204+ sportType ,
205+ durationType ,
206+ tags ,
207+ bars ,
208+ instructions ,
209+ } ) ;
210+ return ;
211+ }
215212
216- const duration =
217- durationType === 'time'
218- ? parseFloat ( attr . Duration )
219- : parseFloat ( attr . Duration ) ;
220- const pace = parseFloat ( attr . pace ) || 0 ;
213+ // Process elements in the order they appear in the XML
214+ workoutElement . elements . forEach ( ( element : any ) => {
215+ const attr = element . attributes ;
221216
222- // Handle text events
223- if ( element . textevent ) {
224- const textEvents = Array . isArray ( element . textevent )
225- ? element . textevent
226- : [ element . textevent ] ;
217+ if ( ! attr ) return ;
227218
228- textEvents . forEach ( ( textEvent : any ) => {
229- const textAttr = textEvent . _attributes ;
230- instructions . push ( {
231- id : uuidv4 ( ) ,
232- text : textAttr . message || '' ,
233- time :
234- durationType === 'time'
235- ? totalTime + parseFloat ( textAttr . timeoffset || 0 )
236- : 0 ,
237- length :
238- durationType === 'distance'
239- ? totalLength + parseFloat ( textAttr . distoffset || 0 )
240- : 0 ,
241- } ) ;
242- } ) ;
243- }
219+ const duration = parseFloat ( attr . Duration ) || 0 ;
220+ const pace = parseFloat ( attr . pace ) || 0 ;
244221
245- // Create bar based on element type
246- if ( elementType === 'SteadyState' ) {
247- bars . push ( {
248- id : uuidv4 ( ) ,
249- type : 'bar' ,
250- time : durationType === 'time' ? duration : 0 ,
251- length : durationType === 'distance' ? duration : 0 ,
252- power : parseFloat ( attr . Power ) ,
253- cadence : parseFloat ( attr . Cadence ) || 0 ,
254- pace : pace ,
255- incline : attr . Incline ? parseFloat ( attr . Incline ) * 100 : 0 ,
256- } ) ;
257- } else if (
258- elementType === 'Warmup' ||
259- elementType === 'Cooldown' ||
260- elementType === 'Ramp'
261- ) {
262- bars . push ( {
222+ // Handle text events
223+ if ( element . elements ) {
224+ const textEvents = element . elements . filter ( ( e : any ) => e . name === 'textevent' ) ;
225+ textEvents . forEach ( ( textEvent : any ) => {
226+ const textAttr = textEvent . attributes ;
227+ instructions . push ( {
263228 id : uuidv4 ( ) ,
264- type : 'trapeze' ,
265- time : durationType === 'time' ? duration : 0 ,
266- length : durationType === 'distance' ? duration : 0 ,
267- startPower : parseFloat ( attr . PowerLow ) ,
268- endPower : parseFloat ( attr . PowerHigh ) ,
269- cadence : parseFloat ( attr . Cadence ) || 0 ,
270- pace : pace ,
271- } ) ;
272- } else if ( elementType === 'IntervalsT' ) {
273- bars . push ( {
274- id : uuidv4 ( ) ,
275- type : 'interval' ,
229+ text : textAttr ?. message || '' ,
276230 time :
277231 durationType === 'time'
278- ? ( parseFloat ( attr . OnDuration ) +
279- parseFloat ( attr . OffDuration ) ) *
280- parseInt ( attr . Repeat )
232+ ? totalTime + parseFloat ( textAttr ?. timeoffset || 0 )
281233 : 0 ,
282234 length :
283235 durationType === 'distance'
284- ? ( parseFloat ( attr . OnDuration ) +
285- parseFloat ( attr . OffDuration ) ) *
286- parseInt ( attr . Repeat )
236+ ? totalLength + parseFloat ( textAttr ?. distoffset || 0 )
287237 : 0 ,
288- repeat : parseInt ( attr . Repeat ) ,
289- onDuration :
290- durationType === 'time'
291- ? parseFloat ( attr . OnDuration )
292- : undefined ,
293- offDuration :
294- durationType === 'time'
295- ? parseFloat ( attr . OffDuration )
296- : undefined ,
297- onLength :
298- durationType === 'distance'
299- ? parseFloat ( attr . OnDuration )
300- : undefined ,
301- offLength :
302- durationType === 'distance'
303- ? parseFloat ( attr . OffDuration )
304- : undefined ,
305- onPower : parseFloat ( attr . OnPower ) ,
306- offPower : parseFloat ( attr . OffPower ) ,
307- cadence : parseFloat ( attr . Cadence ) || 0 ,
308- restingCadence : parseFloat ( attr . CadenceResting ) || 0 ,
309- pace : pace ,
310- } ) ;
311- } else if ( elementType === 'FreeRide' ) {
312- bars . push ( {
313- id : uuidv4 ( ) ,
314- type : 'freeRide' ,
315- time : durationType === 'time' ? duration : 0 ,
316- length : durationType === 'distance' ? duration : 0 ,
317- cadence : parseFloat ( attr . Cadence ) || 0 ,
318238 } ) ;
319- }
320-
321- totalTime += duration ;
322- totalLength += duration ;
323- } ) ;
239+ } ) ;
240+ }
241+
242+ // Create bar based on element type
243+ if ( element . name === 'SteadyState' ) {
244+ bars . push ( {
245+ id : uuidv4 ( ) ,
246+ type : 'bar' ,
247+ time : durationType === 'time' ? duration : 0 ,
248+ length : durationType === 'distance' ? duration : 0 ,
249+ power : parseFloat ( attr . Power ) ,
250+ cadence : parseFloat ( attr . Cadence ) || 0 ,
251+ pace : pace ,
252+ incline : attr . Incline ? parseFloat ( attr . Incline ) * 100 : 0 ,
253+ } ) ;
254+ } else if (
255+ element . name === 'Warmup' ||
256+ element . name === 'Cooldown' ||
257+ element . name === 'Ramp'
258+ ) {
259+ bars . push ( {
260+ id : uuidv4 ( ) ,
261+ type : 'trapeze' ,
262+ time : durationType === 'time' ? duration : 0 ,
263+ length : durationType === 'distance' ? duration : 0 ,
264+ startPower : parseFloat ( attr . PowerLow ) ,
265+ endPower : parseFloat ( attr . PowerHigh ) ,
266+ cadence : parseFloat ( attr . Cadence ) || 0 ,
267+ pace : pace ,
268+ } ) ;
269+ } else if ( element . name === 'IntervalsT' ) {
270+ bars . push ( {
271+ id : uuidv4 ( ) ,
272+ type : 'interval' ,
273+ time :
274+ durationType === 'time'
275+ ? ( parseFloat ( attr . OnDuration ) +
276+ parseFloat ( attr . OffDuration ) ) *
277+ parseInt ( attr . Repeat )
278+ : 0 ,
279+ length :
280+ durationType === 'distance'
281+ ? ( parseFloat ( attr . OnDuration ) +
282+ parseFloat ( attr . OffDuration ) ) *
283+ parseInt ( attr . Repeat )
284+ : 0 ,
285+ repeat : parseInt ( attr . Repeat ) ,
286+ onDuration :
287+ durationType === 'time'
288+ ? parseFloat ( attr . OnDuration )
289+ : undefined ,
290+ offDuration :
291+ durationType === 'time'
292+ ? parseFloat ( attr . OffDuration )
293+ : undefined ,
294+ onLength :
295+ durationType === 'distance'
296+ ? parseFloat ( attr . OnDuration )
297+ : undefined ,
298+ offLength :
299+ durationType === 'distance'
300+ ? parseFloat ( attr . OffDuration )
301+ : undefined ,
302+ onPower : parseFloat ( attr . OnPower ) ,
303+ offPower : parseFloat ( attr . OffPower ) ,
304+ cadence : parseFloat ( attr . Cadence ) || 0 ,
305+ restingCadence : parseFloat ( attr . CadenceResting ) || 0 ,
306+ pace : pace ,
307+ } ) ;
308+ } else if ( element . name === 'FreeRide' ) {
309+ bars . push ( {
310+ id : uuidv4 ( ) ,
311+ type : 'freeRide' ,
312+ time : durationType === 'time' ? duration : 0 ,
313+ length : durationType === 'distance' ? duration : 0 ,
314+ cadence : parseFloat ( attr . Cadence ) || 0 ,
315+ } ) ;
316+ }
317+
318+ totalTime += duration ;
319+ totalLength += duration ;
324320 } ) ;
325321
326322 resolve ( {
0 commit comments