1

I have a .tcx (XML) file, with the following schema:

<Activities>
<Activity>
<Lap StartTime="2015-12-24T08:12:18.969Z">
<TotalTimeSeconds>4069.0</TotalTimeSeconds>
<DistanceMeters>30458.794921875</DistanceMeters>
<MaximumSpeed>43.36123275756836</MaximumSpeed>
<Calories>2286</Calories>
<AverageHeartRateBpm><Value>144</Value></AverageHeartRateBpm><MaximumHeartRateBpm><Value>169</Value></MaximumHeartRateBpm>
<Intensity>Active</Intensity>
<Cadence>87</Cadence>
<TriggerMethod>Manual</TriggerMethod>

<Track>
    <Trackpoint>
        <Time>2015-12-24T08:12:19.969Z</Time>
        <Position><LatitudeDegrees>45.4917</LatitudeDegrees><LongitudeDegrees>9.16198</LongitudeDegrees></Position>
        <AltitudeMeters>124.018</AltitudeMeters>
        <DistanceMeters>0.0</DistanceMeters>
        <SensorState>Present</SensorState>
        <Extensions><TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2"><Watts>0</Watts></TPX></Extensions></Trackpoint>


...
</Track>
</Lap>
</Activity>
</Activities>

and need to change (double) the Watts attribute. Would like a simple python script

2 Answers 2

1

Simply run an XSLT script. No Python loops or expensive XPaths (//) is needed. As information, XSLT is a declarative, special-purpose programming language used specifically to restructure, redesign, or re-format XML documents to various end use needs. Like most general purpose languages such as Java, C#, Perl, PHP, VB, Python comes equipped with an XSLT 1.0 processor in its lxml module.

Below runs an identity transform to copy entire document as is and then multiplies the current value in any Watts node by 2. I declare a namespace doc in XSLT to reference the Watts element.

XSLT (save as .xsl or .xslt)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
               xmlns:doc="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="doc:Watts">
    <xsl:copy>
      <xsl:value-of select=". * 2"/>
    </xsl:copy>
  </xsl:template>

</xsl:transform>

Python Script

import lxml.etree as ET

dom = ET.parse('Input.xml')
xslt = ET.parse('XSLTScript.xsl')

transform = ET.XSLT(xslt)
newdom = transform(dom)

tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True,  xml_declaration=True)

xmlfile = open('Output.xml')
xmlfile.write(tree_out)
xmlfile.close()
Sign up to request clarification or add additional context in comments.

Comments

0

Your last two element tags need to be closing tags, and you have a Watts element not an attribute. Here is how to do it with your file structure.

Python provides the ElementTree library for this. The following script will accomplish what you want:

import xml.etree.ElementTree as ET

tree = ET.parse("test.tcx")

tpxns = "http://www.garmin.com/xmlschemas/ActivityExtension/v2"
for watts in tree.iter("{%s}Watts"%tpxns):
    watts.text = str(2*int(watts.text))

tree.write("testnew.tcx")

Here I import the ElementTree library and use a simpler name for it. The parse function creates an ElementTree object from your file. I walk through the file to find all Watts elements (as these occur in a namespace, I actually need to look for {http://www.garmin.com/xmlschemas/ActivityExtension/v2}Watts, which I build up using string formatting).

When I find such an element, I set the inner text to be twice what the previous value was (converting to an int first and then back to a string).

Finally, I write the new xml file out. I could have overwrote the original file here if I wanted to.

Look over the documentation for the ElementTree module if you need to do anything fancier. It provides very powerful tools for working with XML. There are even more powerful libraries out there if you need more features (I like lxml for example).

1 Comment

Thank you, that's what exactly what I was aiming for. I tried using the ElementTree library, but wasn't able to search for the Watts element, as I was missing the namespace concept.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.