multiply a distance field within a text file?

firstly - thank you for clicking on this topic and I’m hopeful that you can assist with a file I’m attempting to alter and I figure an AppleScript might be able to help?

To try and condense my request - I went for a run on a treadmill today and the data from my smart watch doesn’t reflect the actual distance I covered correctly, so I’m attempting to multiply the field by 1.152 – so the new figure in this field would be 1240.31117

The text in the file below is as follows, I have several hundred of these distance fields to change so I’m hopeful a script can speed up the process?

2019-08-17T23:24:36.000Z 1076.659 151 2.6689999103546143 90

I appreciate if you’re able to help as I’m not that familiar with programming language or how to create a script but would love to learn some day!

Regards, Shaun (sticks1977)

Model: iMac
Browser: Safari 605.1
Operating System: macOS 10.13

I assume that your files indeed are not text files. And the text you provided above is part of a dictionary artificially cut by you. It does not help. Therefore, if you want to be helped, the question is: what is the extension of the name of this file?

the extension of the file is .TCX - I’m able to export from Garmin Connect and open the file in TextEdit to modify the data, hence why I first mentioned it was a text file. Appreciate your reply KniazidisR :slight_smile:

OK, your file contains XML data. Something like that:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

[/url]

    <Activities>
          <Activity Sport="Running">
              <Id>2012-04-18T17:39:02Z</Id>
                  <Lap StartTime="2012-04-18T17:39:02Z">
                      <TotalTimeSeconds>276.03000</TotalTimeSeconds>
                      <DistanceMeters>804.61000</DistanceMeters>
                      <MaximumSpeed>12.00000</MaximumSpeed>
                      <Calories>65.6582</Calories>
                      <Intensity>Active</Intensity>
                      <TriggerMethod>Location</TriggerMethod>
                      <Track>
                          <Trackpoint>
                                  <Time>2012-04-18T17:39:03Z</Time>
                                  <Position>
                                      <LatitudeDegrees>46.850575</LatitudeDegrees>
                                      <LongitudeDegrees>-96.77945</LongitudeDegrees>
                                  </Position>
                                  <AltitudeMeters>0</AltitudeMeters>
                                  <DistanceMeters>0.00000</DistanceMeters>
                                  <SensorState>Absent</SensorState>
                          </Trackpoint>
                          <Trackpoint>
                                  <Time>2012-04-18T17:39:06Z</Time>
                                  <Position>
                                      <LatitudeDegrees>46.850555</LatitudeDegrees>
                                      <LongitudeDegrees>-96.779522</LongitudeDegrees>
                                  </Position>
                                  <AltitudeMeters>0</AltitudeMeters>
                                  <DistanceMeters>5.84000</DistanceMeters>
                                  <SensorState>600</SensorState>
                          </Trackpoint>
                          <Trackpoint>
                                  <Time>2012-04-18T17:39:09Z</Time>
                                  <Position>
                                      <LatitudeDegrees>46.850523</LatitudeDegrees>
                                      <LongitudeDegrees>-96.77959</LongitudeDegrees>
                                  </Position>
                                  <AltitudeMeters>0</AltitudeMeters>
                                  <DistanceMeters>12.06000</DistanceMeters>
                                  <SensorState>600</SensorState>
                          </Trackpoint>

To get and set value of certain key (as key “DistanceMeters”) I should know the full structure of your XML. So provide here your full XML, beginning from <?xml version="1.0" encoding="UTF-8" standalone="no" ?>

If the format is as KniazidisR says, this should work:

use framework "Foundation"
use scripting additions

-- classes, constants, and enums used
property NSXMLDocumentTidyXML : a reference to 1024
property NSXMLNodePreserveAll : a reference to 4.29391875E+9

set theFile to POSIX path of (choose file)
set theURL to current application's NSURL's fileURLWithPath:theFile
set outPath to theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-2.tcx"
set {theDoc, theError} to current application's NSXMLDocument's alloc()'s initWithContentsOfURL:theURL options:NSXMLNodePreserveAll |error|:(reference)
if theDoc is missing value then error theError's localizedDescription() as text
set {theNodes, theError} to theDoc's nodesForXPath:"//DistanceMeters" |error|:(reference)
if theNodes is missing value then error theError's localizedDescription() as text
set nf to current application's NSNumberFormatter's new()
nf's setFormat:"###0.00000#"
repeat with aNode in theNodes
	set oldValue to aNode's stringValue()
	set newValue to (1.152 * (oldValue as real))
	(aNode's setStringValue:(nf's stringFromNumber:newValue))
end repeat
theDoc's XMLString()
set theData to theDoc's XMLData()
theData's writeToFile:outPath atomically:true

That’s also going to re-calculate the Lap distance, as well as the Trackpoint distances. if you don’t want that, change “//DistanceMeters” to “//Trackpoint/DistanceMeters”.

Wow. I was going to parse XML with pure AppleScript. But, probably, pure AppleScript is not able to work with nodes? :slight_smile:

If you mean System Events, it can probably be done — but it will be achingly slow for anything but the smallest of files. XPath simplifies things enormously.

I figure it would be easier if you are able to see the whole file so I have uploaded the TCX file to WeTransfer for you to view.

I saved the script that Shane Stanley kindly created and when I attempted to run the script and click on the TCX file this error appeared:

Appreciate the replies so far and helping me to try and save several hours of work to fix the data.

Regards, Shaun (sticks1977) :slight_smile:

Sorry, I left two vital lines needed at the top of the script:

use framework "Foundation"
use scripting additions

Thanks Shane for your reply - I added the two lines to the top of the script, it started running and all was looking good… until…

Model: iMac
AppleScript: v2.10
Browser: Chrome
Operating System: macOS 10.13

Make that four lines I omitted — I’ve modified the version above to include them,

I wrote pure AppleScript code. But how can I save changes in XML? Need help.


set theXMLFile to POSIX path of (choose file)

tell application "System Events"
	
	set theXMLFile to XML file theXMLFile
	set Activity to XML element 1 of XML element "TrainingCenterDatabase" of theXMLFile
	set ActivitySportRunning to XML element of Activity
	set Laps to XML elements of item 1 of ActivitySportRunning whose name is "Lap"
	
	repeat with i from 1 to (count of Laps)
		set DistanceMeters to (XML elements of item i of Laps whose name is "DistanceMeters")
		repeat with j from 1 to (count of DistanceMeters)
			set DistanceMeter to item j of DistanceMeters
			set oldValue to (value of DistanceMeter) as real
			set newValue to (1.152 * oldValue) as string
			set DistanceMeter's value to newValue
		end repeat
	end repeat
	
end tell

Thanks again Shane - I have ran the script this morning and there is an error with the last line… I am absolutely blown away that people have knowledge like yourself to be able to automate tasks such as these and willing to help and share your time.

The error that appears is as per the screenshot below:

Model: iMac
Browser: Chrome
Operating System: macOS 10.13

My apologies — please try the updated code.

You do not have to apologise!! you have been a great help!

I’m happy to report that it WORKED!!! the script runs perfectly and all the data has been updated to reflect the new distance - thank you so very much Shane.

Regards, Shaun (sticks1977) :smiley:

From memory, the key is something like:

make new property list file with properties {contents:whatEver, name:pathForFile}

Is it possible to add other variables in the same script? For example if I am wanting to multiply the Speed field by the same factor of 1.152?

Change this line:

set {theNodes, theError} to theDoc's nodesForXPath:"//DistanceMeters" |error|:(reference)

to:

set {theNodes, theError} to theDoc's nodesForXPath:"//DistanceMeters|//ns3:Speed" |error|:(reference)

Thanks again Shane for your prompt reply :slight_smile: