source: josm/src/org/openstreetmap/josm/io/OsmReader.java@ 33

Last change on this file since 33 was 33, checked in by imi, 18 years ago
  • prepared for uploading.
  • fixed gpx export/import with uid and modified flag
File size: 7.2 KB
Line 
1package org.openstreetmap.josm.io;
2
3import java.io.IOException;
4import java.io.Reader;
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.StringTokenizer;
8
9import org.jdom.Element;
10import org.jdom.JDOMException;
11import org.jdom.input.SAXBuilder;
12import org.openstreetmap.josm.data.GeoPoint;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.Key;
15import org.openstreetmap.josm.data.osm.LineSegment;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.Track;
19import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
20
21/**
22 * Reads an osm xml stream and construct a DataSet out of it.
23 *
24 * @author imi
25 */
26public class OsmReader {
27
28 /**
29 * The data source from this reader.
30 */
31 public Reader source;
32
33 /**
34 * Construct a parser from a specific data source.
35 * @param source The data source, as example a FileReader to read from a file.
36 */
37 public OsmReader(Reader source) {
38 this.source = source;
39 }
40 static int i;
41 /**
42 * Read the input stream and return a DataSet from the stream.
43 */
44 public DataSet parse() throws JDOMException, IOException {
45 try {
46 final SAXBuilder builder = new SAXBuilder();
47 Element root = builder.build(source).getRootElement();
48 return parseDataSet(root);
49 } catch (NumberFormatException nfe) {
50 throw new JDOMException("NumberFormatException. Probably a tag is missing.", nfe);
51 } catch (NullPointerException npe) {
52 throw new JDOMException("NullPointerException. Probably a tag name mismatch.", npe);
53 } catch (ClassCastException cce) {
54 throw new JDOMException("ClassCastException. Probably a tag does not contain the correct type.", cce);
55 }
56 }
57
58
59 /**
60 * Read one node.
61 * @param e The element to parse
62 * @return The Waypoint read from the element
63 * @throws JDOMException In case of a parsing error.
64 */
65 private Node parseNode(Element e) throws JDOMException {
66 Node data = new Node();
67 data.coor = new GeoPoint(
68 Float.parseFloat(e.getAttributeValue("lat")),
69 Float.parseFloat(e.getAttributeValue("lon")));
70 if (Double.isNaN(data.coor.lat) ||
71 data.coor.lat < -90 || data.coor.lat > 90 ||
72 data.coor.lon < -180 || data.coor.lon > 180)
73 throw new JDOMException("Illegal lat or lon value: "+data.coor.lat+"/"+data.coor.lon);
74 parseCommon(data, e);
75 return data;
76 }
77
78 /**
79 * Parse any (yet unknown) object and return it.
80 */
81 private OsmPrimitive parseObject(Element e, DataSet data) throws JDOMException {
82 if (e.getName().equals("node"))
83 return parseNode(e);
84 else if (e.getName().equals("segment"))
85 return parseLineSegment(e, data);
86 else if (e.getName().equals("track"))
87 return parseTrack(e, data);
88 else if (e.getName().equals("property")) {
89 parseProperty(e, data);
90 return null;
91 }
92 throw new JDOMException("unknown tag: "+e.getName());
93 }
94
95 /**
96 * Read a data set from the element.
97 * @param e The element to parse
98 * @return The DataSet read from the element
99 * @throws JDOMException In case of a parsing error.
100 */
101 private DataSet parseDataSet(Element e) throws JDOMException {
102 DataSet data = new DataSet();
103 AddVisitor visitor = new AddVisitor(data);
104 for (Object o : e.getChildren()) {
105 Element child = (Element)o;
106 if (child.getName().equals("deleted"))
107 for (Object delObj : child.getChildren())
108 data.deleted.add(parseObject((Element)delObj, data));
109 else {
110 OsmPrimitive osm = parseObject(child, data);
111 if (osm != null)
112 osm.visit(visitor);
113 }
114 }
115
116 return data;
117 }
118
119 /**
120 * Parse and return an line segment. The node information of the "from" and
121 * "to" attributes must already be in the dataset.
122 * @param e The line segment element to parse.
123 * @param data The dataset to obtain the node information from.
124 * @return The parsed line segment.
125 * @throws JDOMException In case of parsing errors.
126 */
127 private LineSegment parseLineSegment(Element e, DataSet data) throws JDOMException {
128 long startId = Long.parseLong(e.getAttributeValue("from"));
129 long endId = Long.parseLong(e.getAttributeValue("to"));
130
131 Node start = null, end = null;
132 for (Node n : data.nodes) {
133 if (n.id == startId)
134 start = n;
135 if (n.id == endId)
136 end = n;
137 }
138 if (start == null || end == null)
139 throw new JDOMException("The 'from' or 'to' object has not been transfered before.");
140 LineSegment ls = new LineSegment(start, end);
141 parseCommon(ls, e);
142 return ls;
143 }
144
145 /**
146 * Parse and read a track from the element.
147 *
148 * @param e The element that contain the track.
149 * @param data The DataSet to get segment information from.
150 * @return The parsed track.
151 * @throws JDOMException In case of a parsing error.
152 */
153 private Track parseTrack(Element e, DataSet data) throws JDOMException {
154 Track track = new Track();
155 parseCommon(track, e);
156 for (Object o : e.getChildren("segment")) {
157 Element child = (Element)o;
158 long id = Long.parseLong(child.getAttributeValue("uid"));
159 LineSegment ls = findLineSegment(data.lineSegments, id);
160 track.segments.add(ls);
161 }
162 return track;
163 }
164
165 /**
166 * Parse the common part (properties and uid) of the element.
167 * @param data To store the data in.
168 * @param e The element to extract the common information.
169 * @throws JDOMException In case of a parsing error
170 */
171 private void parseCommon(OsmPrimitive data, Element e) {
172 String suid = e.getAttributeValue("uid");
173 if (suid != null)
174 data.id = Long.parseLong(suid);
175 if (data.id < 0)
176 data.id = 0;
177
178 String propStr = e.getAttributeValue("tags");
179 if (propStr != null && !propStr.equals("")) {
180 data.keys = new HashMap<Key, String>();
181 StringTokenizer st = new StringTokenizer(propStr, ";");
182 while (st.hasMoreTokens()) {
183 StringTokenizer t = new StringTokenizer(st.nextToken(), "=");
184 if (t.countTokens() > 1)
185 data.keys.put(Key.get(t.nextToken()), t.nextToken());
186 else {
187 String token = t.nextToken();
188 if (!" ".equals(token))
189 data.keys.put(Key.get(token), "");
190 }
191 }
192 }
193 }
194
195 /**
196 * Parse a property tag and assign the property to a previous found object.
197 */
198 private void parseProperty(Element e, DataSet data) throws JDOMException {
199 long id = Long.parseLong(e.getAttributeValue("uid"));
200 OsmPrimitive osm = findObject(data, id);
201 Key key = Key.get(e.getAttributeValue("key"));
202 String value =e.getAttributeValue("value");
203 if (value != null) {
204 if (osm.keys == null)
205 osm.keys = new HashMap<Key, String>();
206 osm.keys.put(key, value);
207 }
208 }
209
210 /**
211 * Search for an object in the dataset by comparing the id.
212 */
213 private OsmPrimitive findObject(DataSet data, long id) throws JDOMException {
214 for (OsmPrimitive osm : data.nodes)
215 if (osm.id == id)
216 return osm;
217 for (OsmPrimitive osm : data.lineSegments)
218 if (osm.id == id)
219 return osm;
220 for (OsmPrimitive osm : data.tracks)
221 if (osm.id == id)
222 return osm;
223 for (OsmPrimitive osm : data.deleted)
224 if (osm.id == id)
225 return osm;
226 throw new JDOMException("Unknown object reference: "+id);
227 }
228
229 /**
230 * Search for a segment in a collection by comparing the id.
231 */
232 private LineSegment findLineSegment(Collection<LineSegment> segments, long id) throws JDOMException {
233 for (LineSegment ls : segments)
234 if (ls.id == id)
235 return ls;
236 throw new JDOMException("Unknown line segment reference: "+id);
237 }
238}
Note: See TracBrowser for help on using the repository browser.