source: josm/trunk/src/org/openstreetmap/josm/io/GpxWriter.java@ 6552

Last change on this file since 6552 was 6552, checked in by simon04, 10 years ago

Refactoring: introduce Utils.UTF_8 charset to avoid handling of UnsupportedEncodingException

According to the Javadoc of Charset, every implementation of the Java
platform is required to support UTF-8.

  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedWriter;
7import java.io.OutputStream;
8import java.io.OutputStreamWriter;
9import java.io.PrintWriter;
10import java.util.Collection;
11import java.util.Map;
12import java.util.Map.Entry;
13
14import org.openstreetmap.josm.data.Bounds;
15import org.openstreetmap.josm.data.coor.LatLon;
16import org.openstreetmap.josm.data.gpx.Extensions;
17import org.openstreetmap.josm.data.gpx.GpxConstants;
18import org.openstreetmap.josm.data.gpx.GpxData;
19import org.openstreetmap.josm.data.gpx.GpxLink;
20import org.openstreetmap.josm.data.gpx.GpxRoute;
21import org.openstreetmap.josm.data.gpx.GpxTrack;
22import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
23import org.openstreetmap.josm.data.gpx.IWithAttributes;
24import org.openstreetmap.josm.data.gpx.WayPoint;
25import org.openstreetmap.josm.tools.Utils;
26
27/**
28 * Writes GPX files from GPX data or OSM data.
29 */
30public class GpxWriter extends XmlWriter implements GpxConstants {
31
32 public GpxWriter(PrintWriter out) {
33 super(out);
34 }
35
36 public GpxWriter(OutputStream out) {
37 super(new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, Utils.UTF_8))));
38 }
39
40 private GpxData data;
41 private String indent = "";
42
43 private final static int WAY_POINT = 0;
44 private final static int ROUTE_POINT = 1;
45 private final static int TRACK_POINT = 2;
46
47 public void write(GpxData data) {
48 this.data = data;
49 // We write JOSM specific meta information into gpx 'extensions' elements.
50 // In particular it is noted whether the gpx data is from the OSM server
51 // (so the rendering of clouds of anonymous TrackPoints can be improved)
52 // and some extra synchronization info for export of AudioMarkers.
53 // It is checked in advance, if any extensions are used, so we know whether
54 // a namespace declaration is necessary.
55 boolean hasExtensions = data.fromServer;
56 if (!hasExtensions) {
57 for (WayPoint wpt : data.waypoints) {
58 Extensions extensions = (Extensions) wpt.get(META_EXTENSIONS);
59 if (extensions != null && !extensions.isEmpty()) {
60 hasExtensions = true;
61 break;
62 }
63 }
64 }
65
66 out.println("<?xml version='1.0' encoding='UTF-8'?>");
67 out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" +
68 (hasExtensions ? String.format(" xmlns:josm=\"%s\"%n", JOSM_EXTENSIONS_NAMESPACE_URI) : "") +
69 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" +
70 " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">");
71 indent = " ";
72 writeMetaData();
73 writeWayPoints();
74 writeRoutes();
75 writeTracks();
76 out.print("</gpx>");
77 out.flush();
78 }
79
80 private void writeAttr(IWithAttributes obj) {
81 for (String key : WPT_KEYS) {
82 if (key.equals(META_LINKS)) {
83 @SuppressWarnings("unchecked")
84 Collection<GpxLink> lValue = (Collection<GpxLink>) obj.getCollection(key);
85 if (lValue != null) {
86 for (GpxLink link : lValue) {
87 gpxLink(link);
88 }
89 }
90 } else if (key.equals(META_EXTENSIONS)) {
91 Extensions extensions = (Extensions) obj.get(key);
92 if (extensions != null) {
93 gpxExtensions(extensions);
94 }
95 } else {
96 String value = obj.getString(key);
97 if (value != null) {
98 simpleTag(key, value);
99 }
100 }
101 }
102 }
103
104 @SuppressWarnings("unchecked")
105 private void writeMetaData() {
106 Map<String, Object> attr = data.attr;
107 openln("metadata");
108
109 // write the description
110 if (attr.containsKey(META_DESC)) {
111 simpleTag("desc", (String)attr.get(META_DESC));
112 }
113
114 // write the author details
115 if (attr.containsKey(META_AUTHOR_NAME)
116 || attr.containsKey(META_AUTHOR_EMAIL)) {
117 openln("author");
118 // write the name
119 simpleTag("name", (String) attr.get(META_AUTHOR_NAME));
120 // write the email address
121 if (attr.containsKey(META_AUTHOR_EMAIL)) {
122 String[] tmp = ((String)attr.get(META_AUTHOR_EMAIL)).split("@");
123 if (tmp.length == 2) {
124 inline("email", "id=\"" + tmp[0] + "\" domain=\""+tmp[1]+"\"");
125 }
126 }
127 // write the author link
128 gpxLink((GpxLink) attr.get(META_AUTHOR_LINK));
129 closeln("author");
130 }
131
132 // write the copyright details
133 if (attr.containsKey(META_COPYRIGHT_LICENSE)
134 || attr.containsKey(META_COPYRIGHT_YEAR)) {
135 openAtt("copyright", "author=\""+ attr.get(META_COPYRIGHT_AUTHOR) +"\"");
136 if (attr.containsKey(META_COPYRIGHT_YEAR)) {
137 simpleTag("year", (String) attr.get(META_COPYRIGHT_YEAR));
138 }
139 if (attr.containsKey(META_COPYRIGHT_LICENSE)) {
140 simpleTag("license", encode((String) attr.get(META_COPYRIGHT_LICENSE)));
141 }
142 closeln("copyright");
143 }
144
145 // write links
146 if (attr.containsKey(META_LINKS)) {
147 for (GpxLink link : (Collection<GpxLink>) attr.get(META_LINKS)) {
148 gpxLink(link);
149 }
150 }
151
152 // write keywords
153 if (attr.containsKey(META_KEYWORDS)) {
154 simpleTag("keywords", (String)attr.get(META_KEYWORDS));
155 }
156
157 Bounds bounds = data.recalculateBounds();
158 if (bounds != null) {
159 String b = "minlat=\"" + bounds.getMinLat() + "\" minlon=\"" + bounds.getMinLon() +
160 "\" maxlat=\"" + bounds.getMaxLat() + "\" maxlon=\"" + bounds.getMaxLon() + "\"" ;
161 inline("bounds", b);
162 }
163
164 if (data.fromServer) {
165 openln("extensions");
166 simpleTag("josm:from-server", "true");
167 closeln("extensions");
168 }
169
170 closeln("metadata");
171 }
172
173 private void writeWayPoints() {
174 for (WayPoint pnt : data.waypoints) {
175 wayPoint(pnt, WAY_POINT);
176 }
177 }
178
179 private void writeRoutes() {
180 for (GpxRoute rte : data.routes) {
181 openln("rte");
182 writeAttr(rte);
183 for (WayPoint pnt : rte.routePoints) {
184 wayPoint(pnt, ROUTE_POINT);
185 }
186 closeln("rte");
187 }
188 }
189
190 private void writeTracks() {
191 for (GpxTrack trk : data.tracks) {
192 openln("trk");
193 writeAttr(trk);
194 for (GpxTrackSegment seg : trk.getSegments()) {
195 openln("trkseg");
196 for (WayPoint pnt : seg.getWayPoints()) {
197 wayPoint(pnt, TRACK_POINT);
198 }
199 closeln("trkseg");
200 }
201 closeln("trk");
202 }
203 }
204
205 private void openln(String tag) {
206 open(tag);
207 out.println();
208 }
209
210 private void open(String tag) {
211 out.print(indent + "<" + tag + ">");
212 indent += " ";
213 }
214
215 private void openAtt(String tag, String attributes) {
216 out.println(indent + "<" + tag + " " + attributes + ">");
217 indent += " ";
218 }
219
220 private void inline(String tag, String attributes) {
221 out.println(indent + "<" + tag + " " + attributes + "/>");
222 }
223
224 private void close(String tag) {
225 indent = indent.substring(2);
226 out.print(indent + "</" + tag + ">");
227 }
228
229 private void closeln(String tag) {
230 close(tag);
231 out.println();
232 }
233
234 /**
235 * if content not null, open tag, write encoded content, and close tag
236 * else do nothing.
237 */
238 private void simpleTag(String tag, String content) {
239 if (content != null && content.length() > 0) {
240 open(tag);
241 out.print(encode(content));
242 out.println("</" + tag + ">");
243 indent = indent.substring(2);
244 }
245 }
246
247 /**
248 * output link
249 */
250 private void gpxLink(GpxLink link) {
251 if (link != null) {
252 openAtt("link", "href=\"" + link.uri + "\"");
253 simpleTag("text", link.text);
254 simpleTag("type", link.type);
255 closeln("link");
256 }
257 }
258
259 /**
260 * output a point
261 */
262 private void wayPoint(WayPoint pnt, int mode) {
263 String type;
264 switch(mode) {
265 case WAY_POINT:
266 type = "wpt";
267 break;
268 case ROUTE_POINT:
269 type = "rtept";
270 break;
271 case TRACK_POINT:
272 type = "trkpt";
273 break;
274 default:
275 throw new RuntimeException(tr("Unknown mode {0}.", mode));
276 }
277 if (pnt != null) {
278 LatLon c = pnt.getCoor();
279 String coordAttr = "lat=\"" + c.lat() + "\" lon=\"" + c.lon() + "\"";
280 if (pnt.attr.isEmpty()) {
281 inline(type, coordAttr);
282 } else {
283 openAtt(type, coordAttr);
284 writeAttr(pnt);
285 closeln(type);
286 }
287 }
288 }
289
290 private void gpxExtensions(Extensions extensions) {
291 if (extensions != null && !extensions.isEmpty()) {
292 openln("extensions");
293 for (Entry<String, String> e : extensions.entrySet()) {
294 simpleTag("josm:" + e.getKey(), e.getValue());
295 }
296 closeln("extensions");
297 }
298 }
299}
Note: See TracBrowser for help on using the repository browser.