source: josm/trunk/src/org/openstreetmap/josm/io/GpxReader.java@ 444

Last change on this file since 444 was 444, checked in by framm, 16 years ago
  • patch for better GPX file support by Raphael Mack <ramack@…>
  • dropped support for CSV files
File size: 8.6 KB
Line 
1//License: GPL. Copyright 2007 by Immanuel Scholz and others
2
3//TODO: this is far from complete, but can emulate old RawGps behaviour
4package org.openstreetmap.josm.io;
5
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.io.File;
9import java.io.IOException;
10import java.io.InputStream;
11import java.io.InputStreamReader;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.LinkedList;
15import java.util.Stack;
16import java.util.Map;
17
18import javax.xml.parsers.ParserConfigurationException;
19import javax.xml.parsers.SAXParserFactory;
20
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.gpx.GpxData;
23import org.openstreetmap.josm.data.gpx.GpxLink;
24import org.openstreetmap.josm.data.gpx.GpxTrack;
25import org.openstreetmap.josm.data.gpx.WayPoint;
26import org.openstreetmap.josm.data.gpx.GpxRoute;
27import org.openstreetmap.josm.gui.layer.markerlayer.MarkerProducers;
28import org.xml.sax.Attributes;
29import org.xml.sax.InputSource;
30import org.xml.sax.SAXException;
31import org.xml.sax.helpers.DefaultHandler;
32
33/**
34 * Read a gpx file. Bounds are not read, as we caluclate them. @see GpxData.recalculateBounds()
35 * @author imi, ramack
36 */
37public class GpxReader {
38 // TODO: implement GPX 1.0 parsing
39
40 /**
41 * The resulting gpx data
42 */
43 public GpxData data;
44 public enum state { init, metadata, wpt, rte, trk, ext, author, link, trkseg }
45
46 private class Parser extends DefaultHandler {
47
48 private GpxData currentData;
49 private GpxTrack currentTrack;
50 private Collection<WayPoint> currentTrackSeg;
51 private GpxRoute currentRoute;
52 private WayPoint currentWayPoint;
53
54 private state currentState = state.init;
55
56 private GpxLink currentLink;
57 private Stack<state> states;
58
59 private StringBuffer accumulator = new StringBuffer();
60
61 @Override public void startDocument() {
62 accumulator = new StringBuffer();
63 states = new Stack<state>();
64 currentData = new GpxData();
65 }
66
67 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
68 switch(currentState) {
69 case init:
70 if (qName.equals("metadata")) {
71 states.push(currentState);
72 currentState = state.metadata;
73 } else if (qName.equals("wpt")) {
74 LatLon ll = new LatLon(Double.parseDouble(atts.getValue("lat")), Double.parseDouble(atts.getValue("lon")));
75 states.push(currentState);
76 currentState = state.wpt;
77 currentWayPoint = new WayPoint(ll);
78 } else if (qName.equals("rte")) {
79 states.push(currentState);
80 currentState = state.rte;
81 currentRoute = new GpxRoute();
82 } else if (qName.equals("trk")) {
83 states.push(currentState);
84 currentState = state.trk;
85 currentTrack = new GpxTrack();
86 } else if (qName.equals("extensions")) {
87 states.push(currentState);
88 currentState = state.ext;
89 }
90 break;
91 case author:
92 if (qName.equals("link")) {
93 states.push(currentState);
94 currentState = state.link;
95 currentLink = new GpxLink(atts.getValue("href"));
96 }
97 break;
98 case trk:
99 if (qName.equals("trkseg")) {
100 states.push(currentState);
101 currentState = state.trkseg;
102 currentTrackSeg = new LinkedList<WayPoint>();
103 }
104 if (qName.equals("link")) {
105 states.push(currentState);
106 currentState = state.link;
107 currentLink = new GpxLink(atts.getValue("href"));
108 }
109 break;
110 case metadata:
111 if (qName.equals("author")) {
112 states.push(currentState);
113 currentState = state.author;
114 }
115 break;
116 case trkseg:
117 if (qName.equals("trkpt")) {
118 LatLon ll = new LatLon(Double.parseDouble(atts.getValue("lat")), Double.parseDouble(atts.getValue("lon")));
119 states.push(currentState);
120 currentState = state.wpt;
121 currentWayPoint = new WayPoint(ll);
122 }
123 break;
124 case wpt:
125 if (qName.equals("link")) {
126 states.push(currentState);
127 currentState = state.link;
128 currentLink = new GpxLink(atts.getValue("href"));
129 }
130 break;
131 case rte:
132 if (qName.equals("link")) {
133 states.push(currentState);
134 currentState = state.link;
135 currentLink = new GpxLink(atts.getValue("href"));
136 }
137 if (qName.equals("rtept")) {
138 LatLon ll = new LatLon(Double.parseDouble(atts.getValue("lat")), Double.parseDouble(atts.getValue("lon")));
139 states.push(currentState);
140 currentState = state.wpt;
141 currentWayPoint = new WayPoint(ll);
142 }
143 break;
144 default:
145 }
146 accumulator.setLength(0);
147 }
148
149 @Override public void characters(char[] ch, int start, int length) {
150 accumulator.append(ch, start, length);
151 }
152
153 private Map<String, Object> getAttr() {
154 switch (currentState) {
155 case rte: return currentRoute.attr;
156 case metadata: return currentData.attr;
157 case wpt: return currentWayPoint.attr;
158 case trk: return currentTrack.attr;
159 default: return null;
160 }
161 }
162
163 @Override public void endElement(String namespaceURI, String localName, String qName) {
164 switch (currentState) {
165 case metadata:
166 if (qName.equals("name") || qName.equals("desc") ||
167 qName.equals("time") || qName.equals("keywords")) {
168 currentData.attr.put(qName, accumulator.toString());
169 } else if (qName.equals("metadata")) {
170 currentState = states.pop();
171 }
172 //TODO: parse copyright, bounds, extensions
173 break;
174 case author:
175 if (qName.equals("author")) {
176 currentState = states.pop();
177 } else if (qName.equals("name") || qName.equals("email")) {
178 currentData.attr.put("author" + qName, accumulator.toString());
179 } else if (qName.equals("link")) {
180 currentData.attr.put("authorlink", currentLink);
181 }
182 break;
183 case link:
184 if (qName.equals("text")) {
185 currentLink.text = accumulator.toString();
186 } else if (qName.equals("type")) {
187 currentLink.type = accumulator.toString();
188 } else if (qName.equals("link")) {
189 currentState = states.pop();
190 }
191 if (currentState == state.author) {
192 currentData.attr.put("authorlink", currentLink);
193 } else if (currentState != state.link) {
194 Map<String, Object> attr = getAttr();
195 if (!attr.containsKey("link")) {
196 attr.put("link", new LinkedList<GpxLink>());
197 }
198 ((Collection<GpxLink>) attr.get("link")).add(currentLink);
199 }
200 break;
201 case wpt:
202 if (qName.equals("ele") || qName.equals("time") || qName.equals("desc")
203 || qName.equals("magvar") || qName.equals("geoidheight")
204 || qName.equals("name") || qName.equals("time")
205 || qName.equals("sym") || qName.equals("cmt") || qName.equals("type")) {
206 currentWayPoint.attr.put(qName, accumulator.toString());
207 } else if (qName.equals("rtept")) {
208 currentState = states.pop();
209 currentRoute.routePoints.add(currentWayPoint);
210 } else if (qName.equals("trkpt")) {
211 currentState = states.pop();
212 currentTrackSeg.add(currentWayPoint);
213 } else if (qName.equals("wpt")) {
214 currentState = states.pop();
215 currentData.waypoints.add(currentWayPoint);
216 }
217 break;
218 case trkseg:
219 if (qName.equals("trkseg")) {
220 currentState = states.pop();
221 currentTrack.trackSegs.add(currentTrackSeg);
222 }
223 break;
224 case trk:
225 if (qName.equals("trk")) {
226 currentState = states.pop();
227 currentData.tracks.add(currentTrack);
228 } else if (qName.equals("name") || qName.equals("cmt")
229 || qName.equals("desc") || qName.equals("src")
230 || qName.equals("type") || qName.equals("number")) {
231 currentTrack.attr.put(qName, accumulator.toString());
232 }
233 default:
234 if (qName.equals("wpt")) {
235 currentState = states.pop();
236 } else if (qName.equals("rte")) {
237 currentState = states.pop();
238 currentData.routes.add(currentRoute);
239 } else if (qName.equals("extensions")) {
240 currentState = states.pop();
241 }
242 }
243 }
244
245 @Override public void endDocument() throws SAXException {
246 if (!states.empty()) {
247 throw new SAXException(tr("Parse error: invalid document structure for gpx document"));
248 }
249 data = currentData;
250 }
251 }
252
253 /**
254 * Parse the input stream and store the result in trackData and markerData
255 *
256 * @param relativeMarkerPath The directory to use as relative path for all &lt;wpt&gt;
257 * marker tags. Maybe <code>null</code>, in which case no relative urls are constructed for the markers.
258 */
259 public GpxReader(InputStream source, File relativeMarkerPath) throws SAXException, IOException {
260
261 Parser parser = new Parser();
262 InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8"));
263 try {
264 SAXParserFactory.newInstance().newSAXParser().parse(inputSource, parser);
265 data.storageFile = relativeMarkerPath;
266 } catch (ParserConfigurationException e) {
267 e.printStackTrace(); // broken SAXException chaining
268 throw new SAXException(e);
269 }
270 }
271}
Note: See TracBrowser for help on using the repository browser.