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

Last change on this file since 10228 was 9231, checked in by Don-vip, 8 years ago

javadoc update

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