This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

A solution for combining/merging two TCX files (activies)

Former Member
Former Member
This weekend I needed to adjust my interval workout while it was in progress (yes, I needed a break!) This resulted in me having two different activities and two TCX files for each.

I searched and downloaded various software, but they didn't do exactly what I wanted. (Some didn't preserve the calories, and some turned the workout into a course, etc)

I then tried just copying all the laps from one TCX to the other using notepad, but that didn't work either. The distance was corrupt when I uploaded to Garmin Connect. I realized that the the individual laps in each activity have a cumulative distance tracker. So all I needed to do to make this work is offset the last distance tracked to all of the distances from the other activity.

I created a simple XSLT transform that can be applied to two TCX files and it will create a new merged activity.

Thought I'd share.

(Note, you'll need a XSLT processor like saxon/xalan or others)
  • Hello Cyril,

    The problem was you forgot to check the starting times for each file and number them in increasing order by time.
    You have them reversed so the program merged them in reverse order.
    When the Garmin software encounters that kind of error it stops at the backwards jump in time ignoring the last part of the file.
    I have attached a correctly merged file using the Fit File Repair Tool.
    Each part is now a lap so there are 2 laps.

    Just for grins you could rename your 2 files and merge them again with that JAR tool and compare the results.
    I changed the time on mine by 3 seconds so both files will load into Garmin Connect for comparison if you care.

    Also the coords on your 210 file are way off any roads or paths on your route.
    It has you going thru buildings and down the center of that 8 lane freeway. ;)

    Thank you very much for the tip DATEZZ !
    Works perfectly :)
    Cyril
  • Former Member
    0 Former Member over 11 years ago
    I just read this and had to laugh. Seriously - XSLT, java tools, notepad editing!? :eek:

    Or.. install SportTracks, pick the two workouts, and click "Join".

    Done.

    If you're not happy with the new workout - just edit the track.

    You've got bettter things to do than fiddling with text editing tools - like hitting the road.

    Just sayin.

    I just read this and had to laugh. How low can you go just to sell your software? And you think we will not notice?

    This forum is for helping fellow users. Like the AIM4MIN user who wanted to share something he made for himself and thought maybe can help some other, too.

    And then we have this
    Te easiest way from my point of view

    Your point of what?

    If you only want to sell your stuff, at least do it right, do it with respect to the users here. Say something like "I make this SW, I put a lot of effort on it, it's not free, but it will spare you from a lot of hassle" (especially, if your don't know much about programming and computers), but stop acting like we're supposed to be fools.


    Again thanks to AIM4MIN, and to user DATEZZ. You really are helping.
  • Erm, SportsTrack has a free trial version. I just used it to merge to files and found WATCHMERUN's post really useful.

    CW
  • I can't get the Java tool to work; if I try to combine two *.FIT files, I get an exception about "Content is not allowed in prolog".

    net.sf.saxon.trans.XPathException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
    at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:420)
    at net.sf.saxon.event.Sender.send(Sender.java:180)
    at net.sf.saxon.Controller.transform(Controller.java:1724)
    at CombineActivities.doConvert(CombineActivities.java:160)
    at CombineActivities.access$0(CombineActivities.java:148)
    at CombineActivities$3.actionPerformed(CombineActivities.java:125)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
    Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:400)
    ... 41 more
    ---------
    org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:400)
    at net.sf.saxon.event.Sender.send(Sender.java:180)
    at net.sf.saxon.Controller.transform(Controller.java:1724)
    at CombineActivities.doConvert(CombineActivities.java:160)
    at CombineActivities.access$0(CombineActivities.java:148)
    at CombineActivities$3.actionPerformed(CombineActivities.java:125)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
  • Former Member
    0 Former Member over 11 years ago
    Hello Mike,

    Attach your 2 files to another post here.
    There might be an error in the files that we can correct for you or tell you why you got those errors.
  • It is ridicul that Garmin connect itself doesn't offer this option. :mad:
  • Former Member
    0 Former Member over 11 years ago
    I think the same: Garmin connect could offer this option; we need it for different sports outdoor activities and for work traces.
  • Former Member
    0 Former Member over 11 years ago


    Hello Don,

    I am facing an uploading error on Garmin Connect even after following the instructions and putting a .tcx to the combined activities, can you check what went wrong with my merged activity?

    Thanks in advance!
  • Former Member
    0 Former Member over 11 years ago
    Hello Acydgine,

    You forgot to check the time on each file before combining. You did it backwards.

    There is another problem as well. The first 12 minutes (1.6km) of your run has no coordinates so there will be no track shown on the map for that 1.6km.

    Also, the pathways around the Bedok Reservoir show very plainly on Google Earth but your 620 is recording a very ragged track that does not follow them very well at all.
    The satellite reception might be very poor there because of the tree cover or maybe you were chasing a rabbit? ;)

    So....here ya go. Combined and fixed with the Fit File Repair Tool.
  • Former Member
    0 Former Member over 11 years ago
    Hi Don,

    Thanks for the help. Honestly I still can't figure out what went wrong in the merging, I should spend more time looking into the tcx files to do a detail comparison to know what you fixed. And you mentioned you used the Fit File Repair Tool, is this a paid application? Other than the file sequence, is there something else that i need to check on the output file? I always accidentally push the stop button while adjusting the watch in the middle of a run. So this is not going to be the last time I am merging .tcx files.

    And yes, now that you mentioned, the ragged tracks could be due to the trees and also i notice it happening in another run near to some tall hostel blocks.