Error writing CDATA
Closed this issue · 2 comments
I'm trying to convert tcx files to gpx and have found gpxpy
incredibly useful, however I've encountered a problem when trying to write CDATA. I'm not entirely sure whether its an issue with gpxpy
or not, but thought I'd report it here in case it is.
A self-contained example is...
from lxml.etree import CDATA
from gpxpy import gpx
track = gpx.GPX()
track.name = CDATA('2020-01-05T07:11:05Z')
track.description = CDATA('')
gpx_track = gpx.GPXTrack(name=CDATA('2020-01-05T07:11:05Z'),
description=CDATA(''))
gpx_track.type = CDATA('running')
track.tracks.append(gpx_track)
gpx_segment = gpx.GPXTrackSegment()
gpx_track.segments.append(gpx_segment)
print(track.to_xml())
Which results in...
: print(track.to_xml())
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-486-50a8e75d27b4> in <module>
----> 1 import sys, codecs, os, ast;__pyfile = codecs.open('''/tmp/py54SvrR''', encoding='''utf-8''');__code = __pyfile.read().encode('''utf-8''');__pyfile.close();os.remove('''/tmp/py54SvrR''');__block = ast.parse(__code, '''/home/neil/work/python/tcx2gpx/tmp/test.py''', mode='exec'); __block.body = (__block.body if not isinstance(__block.body[0], ast.If) else __block.body if not isinstance(__block.body[0].test, ast.Name) else __block.body if not __block.body[0].test.id == 'True' else __block.body[0].body) if sys.version_info[0] < 3 else (__block.body if not isinstance(__block.body[0], ast.If) else __block.body if not isinstance(__block.body[0].test, ast.NameConstant) else __block.body if not __block.body[0].test.value is True else __block.body[0].body);__last = __block.body[-1];__isexpr = isinstance(__last,ast.Expr);_ = __block.body.pop() if __isexpr else None;exec(compile(__block, '''/home/neil/work/python/tcx2gpx/tmp/test.py''', mode='exec'));eval(compile(ast.Expression(__last.value), '''/home/neil/work/python/tcx2gpx/tmp/test.py''', mode='eval')) if __isexpr else None
~/work/python/tcx2gpx/tmp/test.py in <module>
~/.virtualenvs/default/lib/python3.6/site-packages/gpxpy/gpx.py in to_xml(self, version, prettyprint)
2724 },
2725 nsmap=self.nsmap,
-> 2726 prettyprint=prettyprint
2727 )
2728
~/.virtualenvs/default/lib/python3.6/site-packages/gpxpy/gpxfield.py in gpx_fields_to_xml(instance, tag, version, custom_attributes, nsmap, prettyprint, indent)
545 xml_value = gpx_field.to_xml(value, version, nsmap,
546 prettyprint=prettyprint,
--> 547 indent=indent + ' ')
548 if xml_value:
549 body.append(xml_value)
~/.virtualenvs/default/lib/python3.6/site-packages/gpxpy/gpxfield.py in to_xml(self, value, version, nsmap, prettyprint, indent)
218 value = self.type_converter.to_string(value)
219 return mod_utils.to_xml(self.tag, content=value, escape=True,
--> 220 prettyprint=prettyprint, indent=indent)
221
222
~/.virtualenvs/default/lib/python3.6/site-packages/gpxpy/utils.py in to_xml(tag, attributes, content, default, escape, prettyprint, indent)
40 else:
41 if escape:
---> 42 result.append(make_str('>%s</%s>' % (mod_saxutils.escape(content), tag)))
43 else:
44 result.append(make_str('>%s</%s>' % (content, tag)))
/usr/lib64/python3.6/xml/sax/saxutils.py in escape(data, entities)
25
26 # must do ampersand first
---> 27 data = data.replace("&", "&")
28 data = data.replace(">", ">")
29 data = data.replace("<", "<")
AttributeError: 'lxml.etree.CDATA' object has no attribute 'replace'
I was expecting the following to be written...
<metadata>
<name><![CDATA[2020-01-05T07:11:05Z]]></name>
<desc><![CDATA[]]></desc>
</metadata>
<trk>
<name><![CDATA[2020-01-05T07:11:05Z]]></name>
<desc><![CDATA[]]></desc>
<type><![CDATA[running]]></type>
I had originally tried writing the CDATA explicitly as in...
track.name = '//<![CDATA[2020-01-05T07:11:05Z]]>'
...but when printing this results in...
<name>//<![CDATA[2019-11-08T08:47:06Z]]></name>
I found the suggestion of using lxml.etree.CDATA()
here, is this the wrong approach to be taking perhaps?
I'm using...
print(gpxpy.__version__)
1.3.5
print(lxml.etree.__version__)
4.4.1
print(sys.version)
3.6.10 (default, Dec 22 2019, 21:38:55)
[GCC 9.2.0]
Unfortunately, this is not possible at the moment.
BTW, Why do you need this? 2020-01-05T07:11:05Z
is a perfectly valid name even without CNAME
.
@tkrajina thanks for taking the time to look at this.
I'm trying to convert tcx files dumped by endomondo.com to gpx for importing to OpenTracks.
I exported a gpx from OpenTracks to check what fields are included and it had...
<metadata>
<name><![CDATA[2019-12-24 08:36]]></name>
<desc><![CDATA[]]></desc>
</metadata>
<trk>
<name><![CDATA[2019-12-24 08:36]]></name>
<desc><![CDATA[]]></desc>
<type><![CDATA[biking]]></type>
<extensions><topografix:color>c0c0c0</topografix:color></extensions>
<trkseg>
...so I was trying to output the tcx in the exact same format.
I hadn't checked whether I had to have the fields exactly but have now tried importing a converted tcx file with the fields as text rather than CDATA
and can successfully import a converted gpx.
I've another issue with writing an .extensions
field but thats minor (it just dictates the colour the track is plotted when opened on a map), but it basically works now which I'm happy about.
My very crude package is here, still need to write some tests for it (can not get my head around Test Driven Development!).
Thanks again for your time.