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

Last change on this file since 14628 was 14459, checked in by Don-vip, 5 years ago

see #16995 - remove unused imports

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