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