Changeset 4413 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2011-09-10T10:56:24+02:00 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/OsmReader.java
r4389 r4413 5 5 6 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 7 8 import java.text.MessageFormat; 8 9 import java.util.ArrayList; … … 12 13 import java.util.List; 13 14 import java.util.Map; 14 15 import javax.xml.parsers.ParserConfigurationException; 16 import javax.xml.parsers.SAXParserFactory; 15 import java.util.regex.Matcher; 16 import java.util.regex.Pattern; 17 18 import javax.xml.stream.XMLInputFactory; 19 import javax.xml.stream.XMLStreamReader; 20 import javax.xml.stream.XMLStreamConstants; 21 import javax.xml.stream.XMLStreamException; 22 import javax.xml.stream.Location; 17 23 18 24 import org.openstreetmap.josm.data.Bounds; … … 37 43 import org.openstreetmap.josm.tools.CheckParameterUtil; 38 44 import org.openstreetmap.josm.tools.DateUtils; 39 import org.xml.sax.Attributes;40 import org.xml.sax.InputSource;41 import org.xml.sax.Locator;42 import org.xml.sax.SAXException;43 import org.xml.sax.SAXParseException;44 import org.xml.sax.helpers.DefaultHandler;45 45 46 46 /** 47 47 * Parser for the Osm Api. Read from an input stream and construct a dataset out of it. 48 48 * 49 * For each xml element, there is a dedicated method. 50 * The XMLStreamReader cursor points to the start of the element, when the method is 51 * entered, and it must point to the end of the same element, when it is exited. 49 52 */ 50 53 public class OsmReader { 51 /**52 * The dataset to add parsed objects to.53 */54 private DataSet ds = new DataSet();55 56 /**57 * Replies the parsed data set58 *59 * @return the parsed data set60 */61 public DataSet getDataSet() {62 return ds;63 }64 65 /** the map from external ids to read OsmPrimitives. External ids are66 * longs too, but in contrast to internal ids negative values are used67 * to identify primitives unknown to the OSM server68 */69 private Map<PrimitiveId, OsmPrimitive> externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>();70 71 /**72 * constructor (for private use only)73 *74 * @see #parseDataSet(InputStream, DataSet, ProgressMonitor)75 * @see #parseDataSetOsm(InputStream, DataSet, ProgressMonitor)76 */77 private OsmReader() {78 externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>();79 }80 54 81 55 /** … … 90 64 91 65 /** 66 * The dataset to add parsed objects to. 67 */ 68 private DataSet ds = new DataSet(); 69 70 private XMLStreamReader parser; 71 72 /** the map from external ids to read OsmPrimitives. External ids are 73 * longs too, but in contrast to internal ids negative values are used 74 * to identify primitives unknown to the OSM server 75 */ 76 private Map<PrimitiveId, OsmPrimitive> externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>(); 77 78 /** 92 79 * Data structure for the remaining way objects 93 80 */ … … 99 86 private Map<Long, Collection<RelationMemberData>> relations = new HashMap<Long, Collection<RelationMemberData>>(); 100 87 101 private class Parser extends DefaultHandler { 102 private Locator locator; 88 /** 89 * constructor (for private use only) 90 * 91 * @see #parseDataSet(InputStream, DataSet, ProgressMonitor) 92 */ 93 private OsmReader() { 94 externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>(); 95 } 96 97 public void setParser(XMLStreamReader parser) { 98 this.parser = parser; 99 } 100 101 /** 102 * Replies the parsed data set 103 * 104 * @return the parsed data set 105 */ 106 public DataSet getDataSet() { 107 return ds; 108 } 109 110 protected void throwException(String msg) throws XMLStreamException { 111 throw new OsmParsingException(msg, parser.getLocation()); 112 } 113 114 public void parse() throws XMLStreamException { 115 int event = parser.getEventType(); 116 while (true) { 117 if (event == XMLStreamConstants.START_ELEMENT) { 118 if (parser.getLocalName().equals("osm") || parser.getLocalName().equals("osmChange")) { 119 parseOsm(); 120 } else { 121 parseUnkown(); 122 } 123 } else if (event == XMLStreamConstants.END_ELEMENT) { 124 return; 125 } 126 if (parser.hasNext()) { 127 event = parser.next(); 128 } else { 129 break; 130 } 131 } 132 parser.close(); 133 } 134 135 private void parseOsm() throws XMLStreamException { 136 String v = parser.getAttributeValue(null, "version"); 137 if (v == null) { 138 throwException(tr("Missing mandatory attribute ''{0}''.", "version")); 139 } 140 if (!(v.equals("0.5") || v.equals("0.6"))) { 141 throwException(tr("Unsupported version: {0}", v)); 142 } 143 String generator = parser.getAttributeValue(null, "generator"); 144 ds.setVersion(v); 145 while (true) { 146 int event = parser.next(); 147 if (event == XMLStreamConstants.START_ELEMENT) { 148 if (parser.getLocalName().equals("bounds")) { 149 parseBounds(generator); 150 } else if (parser.getLocalName().equals("node")) { 151 parseNode(); 152 } else if (parser.getLocalName().equals("way")) { 153 parseWay(); 154 } else if (parser.getLocalName().equals("relation")) { 155 parseRelation(); 156 } else { 157 parseUnkown(); 158 } 159 } else if (event == XMLStreamConstants.END_ELEMENT) { 160 return; 161 } 162 } 163 } 164 165 private void parseBounds(String generator) throws XMLStreamException { 166 String minlon = parser.getAttributeValue(null, "minlon"); 167 String minlat = parser.getAttributeValue(null, "minlat"); 168 String maxlon = parser.getAttributeValue(null, "maxlon"); 169 String maxlat = parser.getAttributeValue(null, "maxlat"); 170 String origin = parser.getAttributeValue(null, "origin"); 171 if (minlon != null && maxlon != null && minlat != null && maxlat != null) { 172 if (origin == null) { 173 origin = generator; 174 } 175 Bounds bounds = new Bounds( 176 Double.parseDouble(minlat), Double.parseDouble(minlon), 177 Double.parseDouble(maxlat), Double.parseDouble(maxlon)); 178 if (bounds.isOutOfTheWorld()) { 179 Bounds copy = new Bounds(bounds); 180 bounds.normalize(); 181 System.out.println("Bbox " + copy + " is out of the world, normalized to " + bounds); 182 } 183 DataSource src = new DataSource(bounds, origin); 184 ds.dataSources.add(src); 185 } else { 186 throwException(tr( 187 "Missing mandatory attributes on element ''bounds''. Got minlon=''{0}'',minlat=''{1}'',maxlon=''{3}'',maxlat=''{4}'', origin=''{5}''.", 188 minlon, minlat, maxlon, maxlat, origin 189 )); 190 } 191 jumpToEnd(); 192 } 193 194 private void parseNode() throws XMLStreamException { 195 NodeData nd = new NodeData(); 196 nd.setCoor(new LatLon(Double.parseDouble(parser.getAttributeValue(null, "lat")), Double.parseDouble(parser.getAttributeValue(null, "lon")))); 197 readCommon(nd); 198 Node n = new Node(nd.getId(), nd.getVersion()); 199 n.setVisible(nd.isVisible()); 200 n.load(nd); 201 externalIdMap.put(nd.getPrimitiveId(), n); 202 while (true) { 203 int event = parser.next(); 204 if (event == XMLStreamConstants.START_ELEMENT) { 205 if (parser.getLocalName().equals("tag")) { 206 parseTag(n); 207 } else { 208 parseUnkown(); 209 } 210 } else if (event == XMLStreamConstants.END_ELEMENT) { 211 return; 212 } 213 } 214 } 215 216 private void parseWay() throws XMLStreamException { 217 WayData wd = new WayData(); 218 readCommon(wd); 219 Way w = new Way(wd.getId(), wd.getVersion()); 220 w.setVisible(wd.isVisible()); 221 w.load(wd); 222 externalIdMap.put(wd.getPrimitiveId(), w); 223 224 Collection<Long> nodeIds = new ArrayList<Long>(); 225 while (true) { 226 int event = parser.next(); 227 if (event == XMLStreamConstants.START_ELEMENT) { 228 if (parser.getLocalName().equals("nd")) { 229 nodeIds.add(parseWayNode(w)); 230 } else if (parser.getLocalName().equals("tag")) { 231 parseTag(w); 232 } else { 233 parseUnkown(); 234 } 235 } else if (event == XMLStreamConstants.END_ELEMENT) { 236 break; 237 } 238 } 239 if (w.isDeleted() && nodeIds.size() > 0) { 240 System.out.println(tr("Deleted way {0} contains nodes", w.getUniqueId())); 241 nodeIds = new ArrayList<Long>(); 242 } 243 ways.put(wd.getUniqueId(), nodeIds); 244 } 245 246 private long parseWayNode(Way w) throws XMLStreamException { 247 if (parser.getAttributeValue(null, "ref") == null) { 248 throwException( 249 tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}.", "ref", w.getUniqueId()) 250 ); 251 } 252 long id = getLong("ref"); 253 if (id == 0) { 254 throwException( 255 tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) 256 ); 257 } 258 jumpToEnd(); 259 return id; 260 } 261 262 private void parseRelation() throws XMLStreamException { 263 RelationData rd = new RelationData(); 264 readCommon(rd); 265 Relation r = new Relation(rd.getId(), rd.getVersion()); 266 r.setVisible(rd.isVisible()); 267 r.load(rd); 268 externalIdMap.put(rd.getPrimitiveId(), r); 269 270 Collection<RelationMemberData> members = new ArrayList<RelationMemberData>(); 271 while (true) { 272 int event = parser.next(); 273 if (event == XMLStreamConstants.START_ELEMENT) { 274 if (parser.getLocalName().equals("member")) { 275 members.add(parseRelationMember(r)); 276 } else if (parser.getLocalName().equals("tag")) { 277 parseTag(r); 278 } else { 279 parseUnkown(); 280 } 281 } else if (event == XMLStreamConstants.END_ELEMENT) { 282 break; 283 } 284 } 285 if (r.isDeleted() && members.size() > 0) { 286 System.out.println(tr("Deleted relation {0} contains members", r.getUniqueId())); 287 members = new ArrayList<RelationMemberData>(); 288 } 289 relations.put(rd.getUniqueId(), members); 290 } 291 292 private RelationMemberData parseRelationMember(Relation r) throws XMLStreamException { 293 RelationMemberData emd = new RelationMemberData(); 294 String value = parser.getAttributeValue(null, "ref"); 295 if (value == null) { 296 throwException(tr("Missing attribute ''ref'' on member in relation {0}.",r.getUniqueId())); 297 } 298 try { 299 emd.id = Long.parseLong(value); 300 } catch(NumberFormatException e) { 301 throwException(tr("Illegal value for attribute ''ref'' on member in relation {0}. Got {1}", Long.toString(r.getUniqueId()),value)); 302 } 303 value = parser.getAttributeValue(null, "type"); 304 if (value == null) { 305 throwException(tr("Missing attribute ''type'' on member {0} in relation {1}.", Long.toString(emd.id), Long.toString(r.getUniqueId()))); 306 } 307 try { 308 emd.type = OsmPrimitiveType.fromApiTypeName(value); 309 } catch(IllegalArgumentException e) { 310 throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.", Long.toString(emd.id), Long.toString(r.getUniqueId()), value)); 311 } 312 value = parser.getAttributeValue(null, "role"); 313 emd.role = value; 314 315 if (emd.id == 0) { 316 throwException(tr("Incomplete <member> specification with ref=0")); 317 } 318 jumpToEnd(); 319 return emd; 320 } 321 322 private void parseTag(OsmPrimitive osm) throws XMLStreamException { 323 String key = parser.getAttributeValue(null, "k"); 324 String value = parser.getAttributeValue(null, "v"); 325 if (key == null || value == null) { 326 throwException(tr("Missing key or value attribute in tag.")); 327 } 328 osm.put(key.intern(), value.intern()); 329 jumpToEnd(); 330 } 331 332 /** 333 * When cursor is at the start of an element, moves it to the end tag of that element. 334 * Nested content is skipped. 335 * 336 * This is basically the same code as parseUnkown(), except for the warnings, which 337 * are displayed for inner elements and not at top level. 338 */ 339 private void jumpToEnd() throws XMLStreamException { 340 while (true) { 341 int event = parser.next(); 342 if (event == XMLStreamConstants.START_ELEMENT) { 343 parseUnkown(); 344 } else if (event == XMLStreamConstants.END_ELEMENT) { 345 return; 346 } 347 } 348 } 349 350 private void parseUnkown() throws XMLStreamException { 351 parseUnkown(true); 352 } 353 354 private void parseUnkown(boolean printWarning) throws XMLStreamException { 355 if (printWarning) { 356 System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", parser.getLocalName())); 357 } 358 while (true) { 359 int event = parser.next(); 360 if (event == XMLStreamConstants.START_ELEMENT) { 361 parseUnkown(false); /* no more warning for inner elements */ 362 } else if (event == XMLStreamConstants.END_ELEMENT) { 363 return; 364 } 365 } 366 } 367 368 private User createUser(String uid, String name) throws XMLStreamException { 369 if (uid == null) { 370 if (name == null) 371 return null; 372 return User.createLocalUser(name); 373 } 374 try { 375 long id = Long.parseLong(uid); 376 return User.createOsmUser(id, name); 377 } catch(NumberFormatException e) { 378 throwException(MessageFormat.format("Illegal value for attribute ''uid''. Got ''{0}''.", uid)); 379 } 380 return null; 381 } 382 383 /** 384 * Read out the common attributes and put them into current OsmPrimitive. 385 */ 386 private void readCommon(PrimitiveData current) throws XMLStreamException { 387 current.setId(getLong("id")); 388 if (current.getUniqueId() == 0) { 389 throwException(tr("Illegal object with ID=0.")); 390 } 391 392 String time = parser.getAttributeValue(null, "timestamp"); 393 if (time != null && time.length() != 0) { 394 current.setTimestamp(DateUtils.fromString(time)); 395 } 396 397 // user attribute added in 0.4 API 398 String user = parser.getAttributeValue(null, "user"); 399 // uid attribute added in 0.6 API 400 String uid = parser.getAttributeValue(null, "uid"); 401 current.setUser(createUser(uid, user)); 402 403 // visible attribute added in 0.4 API 404 String visible = parser.getAttributeValue(null, "visible"); 405 if (visible != null) { 406 current.setVisible(Boolean.parseBoolean(visible)); 407 } 408 409 String versionString = parser.getAttributeValue(null, "version"); 410 int version = 0; 411 if (versionString != null) { 412 try { 413 version = Integer.parseInt(versionString); 414 } catch(NumberFormatException e) { 415 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString)); 416 } 417 if (ds.getVersion().equals("0.6")){ 418 if (version <= 0 && current.getUniqueId() > 0) { 419 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString)); 420 } else if (version < 0 && current.getUniqueId() <= 0) { 421 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 0, "0.6")); 422 version = 0; 423 } 424 } else if (ds.getVersion().equals("0.5")) { 425 if (version <= 0 && current.getUniqueId() > 0) { 426 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 1, "0.5")); 427 version = 1; 428 } else if (version < 0 && current.getUniqueId() <= 0) { 429 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 0, "0.5")); 430 version = 0; 431 } 432 } else { 433 // should not happen. API version has been checked before 434 throwException(tr("Unknown or unsupported API version. Got {0}.", ds.getVersion())); 435 } 436 } else { 437 // version expected for OSM primitives with an id assigned by the server (id > 0), since API 0.6 438 // 439 if (current.getUniqueId() > 0 && ds.getVersion() != null && ds.getVersion().equals("0.6")) { 440 throwException(tr("Missing attribute ''version'' on OSM primitive with ID {0}.", Long.toString(current.getUniqueId()))); 441 } else if (current.getUniqueId() > 0 && ds.getVersion() != null && ds.getVersion().equals("0.5")) { 442 // default version in 0.5 files for existing primitives 443 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 1, "0.5")); 444 version= 1; 445 } else if (current.getUniqueId() <= 0 && ds.getVersion() != null && ds.getVersion().equals("0.5")) { 446 // default version in 0.5 files for new primitives, no warning necessary. This is 447 // (was) legal in API 0.5 448 version= 0; 449 } 450 } 451 current.setVersion(version); 452 453 String action = parser.getAttributeValue(null, "action"); 454 if (action == null) { 455 // do nothing 456 } else if (action.equals("delete")) { 457 current.setDeleted(true); 458 current.setModified(current.isVisible()); 459 } else if (action.equals("modify")) { 460 current.setModified(true); 461 } 462 463 String v = parser.getAttributeValue(null, "changeset"); 464 if (v == null) { 465 current.setChangesetId(0); 466 } else { 467 try { 468 current.setChangesetId(Integer.parseInt(v)); 469 } catch(NumberFormatException e) { 470 if (current.getUniqueId() <= 0) { 471 // for a new primitive we just log a warning 472 System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId())); 473 current.setChangesetId(0); 474 } else { 475 // for an existing primitive this is a problem 476 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v)); 477 } 478 } 479 if (current.getChangesetId() <=0) { 480 if (current.getUniqueId() <= 0) { 481 // for a new primitive we just log a warning 482 System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId())); 483 current.setChangesetId(0); 484 } else { 485 // for an existing primitive this is a problem 486 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v)); 487 } 488 } 489 } 490 } 491 492 private long getLong(String name) throws XMLStreamException { 493 String value = parser.getAttributeValue(null, name); 494 if (value == null) { 495 throwException(tr("Missing required attribute ''{0}''.",name)); 496 } 497 try { 498 return Long.parseLong(value); 499 } catch(NumberFormatException e) { 500 throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''.",name, value)); 501 } 502 return 0; // should not happen 503 } 504 505 private static class OsmParsingException extends XMLStreamException { 506 public OsmParsingException() { 507 super(); 508 } 509 510 public OsmParsingException(String msg) { 511 super(msg); 512 } 513 514 public OsmParsingException(String msg, Location location) { 515 super(msg); /* cannot use super(msg, location) because it messes with the message preventing localization */ 516 this.location = location; 517 } 518 519 public OsmParsingException(String msg, Location location, Throwable th) { 520 super(msg, th); 521 this.location = location; 522 } 523 524 public OsmParsingException(String msg, Throwable th) { 525 super(msg, th); 526 } 527 528 public OsmParsingException(Throwable th) { 529 super(th); 530 } 103 531 104 532 @Override 105 public void setDocumentLocator(Locator locator) { 106 this.locator = locator; 107 } 108 109 protected void throwException(String msg) throws OsmDataParsingException{ 110 throw new OsmDataParsingException(msg).rememberLocation(locator); 111 } 112 /** 113 * The current osm primitive to be read. 114 */ 115 private OsmPrimitive currentPrimitive; 116 private long currentExternalId; 117 private String generator; 118 119 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 120 121 try { 122 if (qName.equals("osm") || qName.equals("osmChange")) { 123 if (atts == null) { 124 throwException(tr("Missing mandatory attribute ''{0}'' of XML element {1}.", "version", qName)); 125 } 126 String v = atts.getValue("version"); 127 if (v == null) { 128 throwException(tr("Missing mandatory attribute ''{0}''.", "version")); 129 } 130 if (!(v.equals("0.5") || v.equals("0.6"))) { 131 throwException(tr("Unsupported version: {0}", v)); 132 } 133 // save generator attribute for later use when creating DataSource objects 134 generator = atts.getValue("generator"); 135 ds.setVersion(v); 136 137 } else if (qName.equals("bounds")) { 138 // new style bounds. 139 String minlon = atts.getValue("minlon"); 140 String minlat = atts.getValue("minlat"); 141 String maxlon = atts.getValue("maxlon"); 142 String maxlat = atts.getValue("maxlat"); 143 String origin = atts.getValue("origin"); 144 if (minlon != null && maxlon != null && minlat != null && maxlat != null) { 145 if (origin == null) { 146 origin = generator; 147 } 148 Bounds bounds = new Bounds( 149 Double.parseDouble(minlat), Double.parseDouble(minlon), 150 Double.parseDouble(maxlat), Double.parseDouble(maxlon)); 151 if (bounds.isOutOfTheWorld()) { 152 Bounds copy = new Bounds(bounds); 153 bounds.normalize(); 154 System.out.println("Bbox " + copy + " is out of the world, normalized to " + bounds); 155 } 156 DataSource src = new DataSource(bounds, origin); 157 ds.dataSources.add(src); 158 } else { 159 throwException(tr( 160 "Missing mandatory attributes on element ''bounds''. Got minlon=''{0}'',minlat=''{1}'',maxlon=''{3}'',maxlat=''{4}'', origin=''{5}''.", 161 minlon, minlat, maxlon, maxlat, origin 162 )); 163 } 164 165 // ---- PARSING NODES AND WAYS ---- 166 167 } else if (qName.equals("node")) { 168 NodeData nd = new NodeData(); 169 nd.setCoor(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"))); 170 readCommon(atts, nd); 171 Node n = new Node(nd.getId(), nd.getVersion()); 172 n.setVisible(nd.isVisible()); 173 n.load(nd); 174 externalIdMap.put(nd.getPrimitiveId(), n); 175 currentPrimitive = n; 176 currentExternalId = nd.getUniqueId(); 177 } else if (qName.equals("way")) { 178 WayData wd = new WayData(); 179 readCommon(atts, wd); 180 Way w = new Way(wd.getId(), wd.getVersion()); 181 w.setVisible(wd.isVisible()); 182 w.load(wd); 183 externalIdMap.put(wd.getPrimitiveId(), w); 184 ways.put(wd.getUniqueId(), new ArrayList<Long>()); 185 currentPrimitive = w; 186 currentExternalId = wd.getUniqueId(); 187 } else if (qName.equals("nd")) { 188 Collection<Long> list = ways.get(currentExternalId); 189 if (list == null) { 190 throwException( 191 tr("Found XML element <nd> not as direct child of element <way>.") 192 ); 193 } 194 if (atts.getValue("ref") == null) { 195 throwException( 196 tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}.", "ref", currentPrimitive.getUniqueId()) 197 ); 198 } 199 long id = getLong(atts, "ref"); 200 if (id == 0) { 201 throwException( 202 tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) 203 ); 204 } 205 if (currentPrimitive.isDeleted()) { 206 System.out.println(tr("Deleted way {0} contains nodes", currentPrimitive.getUniqueId())); 207 } else { 208 list.add(id); 209 } 210 211 // ---- PARSING RELATIONS ---- 212 213 } else if (qName.equals("relation")) { 214 RelationData rd = new RelationData(); 215 readCommon(atts, rd); 216 Relation r = new Relation(rd.getId(), rd.getVersion()); 217 r.setVisible(rd.isVisible()); 218 r.load(rd); 219 externalIdMap.put(rd.getPrimitiveId(), r); 220 relations.put(rd.getUniqueId(), new LinkedList<RelationMemberData>()); 221 currentPrimitive = r; 222 currentExternalId = rd.getUniqueId(); 223 } else if (qName.equals("member")) { 224 Collection<RelationMemberData> list = relations.get(currentExternalId); 225 if (list == null) { 226 throwException( 227 tr("Found XML element <member> not as direct child of element <relation>.") 228 ); 229 } 230 RelationMemberData emd = new RelationMemberData(); 231 String value = atts.getValue("ref"); 232 if (value == null) { 233 throwException(tr("Missing attribute ''ref'' on member in relation {0}.",currentPrimitive.getUniqueId())); 234 } 235 try { 236 emd.id = Long.parseLong(value); 237 } catch(NumberFormatException e) { 238 throwException(tr("Illegal value for attribute ''ref'' on member in relation {0}. Got {1}", Long.toString(currentPrimitive.getUniqueId()),value)); 239 } 240 value = atts.getValue("type"); 241 if (value == null) { 242 throwException(tr("Missing attribute ''type'' on member {0} in relation {1}.", Long.toString(emd.id), Long.toString(currentPrimitive.getUniqueId()))); 243 } 244 try { 245 emd.type = OsmPrimitiveType.fromApiTypeName(value); 246 } catch(IllegalArgumentException e) { 247 throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.", Long.toString(emd.id), Long.toString(currentPrimitive.getUniqueId()), value)); 248 } 249 value = atts.getValue("role"); 250 emd.role = value; 251 252 if (emd.id == 0) { 253 throwException(tr("Incomplete <member> specification with ref=0")); 254 } 255 256 if (currentPrimitive.isDeleted()) { 257 System.out.println(tr("Deleted relation {0} contains members", currentPrimitive.getUniqueId())); 258 } else { 259 list.add(emd); 260 } 261 262 // ---- PARSING TAGS (applicable to all objects) ---- 263 264 } else if (qName.equals("tag")) { 265 String key = atts.getValue("k"); 266 String value = atts.getValue("v"); 267 if (key == null || value == null) { 268 throwException(tr("Missing key or value attribute in tag.")); 269 } 270 if (currentPrimitive != null) { 271 currentPrimitive.put(key.intern(), value.intern()); 272 } 273 } else { 274 System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", qName)); 275 } 276 } catch (Exception e) { 277 throw new SAXParseException(e.getMessage(), locator, e); 278 } 279 } 280 281 private double getDouble(Attributes atts, String value) { 282 return Double.parseDouble(atts.getValue(value)); 283 } 284 285 private User createUser(String uid, String name) throws SAXException { 286 if (uid == null) { 287 if (name == null) 288 return null; 289 return User.createLocalUser(name); 290 } 291 try { 292 long id = Long.parseLong(uid); 293 return User.createOsmUser(id, name); 294 } catch(NumberFormatException e) { 295 throwException(MessageFormat.format("Illegal value for attribute ''uid''. Got ''{0}''.", uid)); 296 } 297 return null; 298 } 299 /** 300 * Read out the common attributes from atts and put them into this.current. 301 */ 302 void readCommon(Attributes atts, PrimitiveData current) throws SAXException { 303 current.setId(getLong(atts, "id")); 304 if (current.getUniqueId() == 0) { 305 throwException(tr("Illegal object with ID=0.")); 306 } 307 308 String time = atts.getValue("timestamp"); 309 if (time != null && time.length() != 0) { 310 current.setTimestamp(DateUtils.fromString(time)); 311 } 312 313 // user attribute added in 0.4 API 314 String user = atts.getValue("user"); 315 // uid attribute added in 0.6 API 316 String uid = atts.getValue("uid"); 317 current.setUser(createUser(uid, user)); 318 319 // visible attribute added in 0.4 API 320 String visible = atts.getValue("visible"); 321 if (visible != null) { 322 current.setVisible(Boolean.parseBoolean(visible)); 323 } 324 325 String versionString = atts.getValue("version"); 326 int version = 0; 327 if (versionString != null) { 328 try { 329 version = Integer.parseInt(versionString); 330 } catch(NumberFormatException e) { 331 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString)); 332 } 333 if (ds.getVersion().equals("0.6")){ 334 if (version <= 0 && current.getUniqueId() > 0) { 335 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString)); 336 } else if (version < 0 && current.getUniqueId() <= 0) { 337 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 0, "0.6")); 338 version = 0; 339 } 340 } else if (ds.getVersion().equals("0.5")) { 341 if (version <= 0 && current.getUniqueId() > 0) { 342 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 1, "0.5")); 343 version = 1; 344 } else if (version < 0 && current.getUniqueId() <= 0) { 345 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 0, "0.5")); 346 version = 0; 347 } 348 } else { 349 // should not happen. API version has been checked before 350 throwException(tr("Unknown or unsupported API version. Got {0}.", ds.getVersion())); 351 } 352 } else { 353 // version expected for OSM primitives with an id assigned by the server (id > 0), since API 0.6 354 // 355 if (current.getUniqueId() > 0 && ds.getVersion() != null && ds.getVersion().equals("0.6")) { 356 throwException(tr("Missing attribute ''version'' on OSM primitive with ID {0}.", Long.toString(current.getUniqueId()))); 357 } else if (current.getUniqueId() > 0 && ds.getVersion() != null && ds.getVersion().equals("0.5")) { 358 // default version in 0.5 files for existing primitives 359 System.out.println(tr("WARNING: Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.", current.getUniqueId(), version, 1, "0.5")); 360 version= 1; 361 } else if (current.getUniqueId() <= 0 && ds.getVersion() != null && ds.getVersion().equals("0.5")) { 362 // default version in 0.5 files for new primitives, no warning necessary. This is 363 // (was) legal in API 0.5 364 version= 0; 365 } 366 } 367 current.setVersion(version); 368 369 String action = atts.getValue("action"); 370 if (action == null) { 371 // do nothing 372 } else if (action.equals("delete")) { 373 current.setDeleted(true); 374 current.setModified(current.isVisible()); 375 } else if (action.equals("modify")) { 376 current.setModified(true); 377 } 378 379 String v = atts.getValue("changeset"); 380 if (v == null) { 381 current.setChangesetId(0); 382 } else { 383 try { 384 current.setChangesetId(Integer.parseInt(v)); 385 } catch(NumberFormatException e) { 386 if (current.getUniqueId() <= 0) { 387 // for a new primitive we just log a warning 388 System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId())); 389 current.setChangesetId(0); 390 } else { 391 // for an existing primitive this is a problem 392 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v)); 393 } 394 } 395 if (current.getChangesetId() <=0) { 396 if (current.getUniqueId() <= 0) { 397 // for a new primitive we just log a warning 398 System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId())); 399 current.setChangesetId(0); 400 } else { 401 // for an existing primitive this is a problem 402 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v)); 403 } 404 } 405 } 406 } 407 408 private long getLong(Attributes atts, String name) throws SAXException { 409 String value = atts.getValue(name); 410 if (value == null) { 411 throwException(tr("Missing required attribute ''{0}''.",name)); 412 } 413 try { 414 return Long.parseLong(value); 415 } catch(NumberFormatException e) { 416 throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''.",name, value)); 417 } 418 return 0; // should not happen 533 public String getMessage() { 534 String msg = super.getMessage(); 535 if (msg == null) { 536 msg = getClass().getName(); 537 } 538 if (getLocation() == null) 539 return msg; 540 msg = msg + " " + tr("(at line {0}, column {1})", getLocation().getLineNumber(), getLocation().getColumnNumber()); 541 return msg; 542 } 543 } 544 545 /** 546 * Processes the parsed nodes after parsing. Just adds them to 547 * the dataset 548 * 549 */ 550 protected void processNodesAfterParsing() { 551 for (OsmPrimitive primitive: externalIdMap.values()) { 552 if (primitive instanceof Node) { 553 this.ds.addPrimitive(primitive); 554 } 419 555 } 420 556 } … … 462 598 463 599 /** 464 * Processes the parsed nodes after parsing. Just adds them to465 * the dataset466 *467 */468 protected void processNodesAfterParsing() {469 for (OsmPrimitive primitive: externalIdMap.values()) {470 if (primitive instanceof Node) {471 this.ds.addPrimitive(primitive);472 }473 }474 }475 476 /**477 600 * Completes the parsed relations with its members. 478 601 * … … 562 685 progressMonitor.indeterminateSubTask(tr("Parsing OSM data...")); 563 686 564 InputSource inputSource = new InputSource(UTFInputStreamReader.create(source, "UTF-8")); 565 SAXParserFactory.newInstance().newSAXParser().parse(inputSource, reader.new Parser()); 687 InputStreamReader ir = UTFInputStreamReader.create(source, "UTF-8"); 688 XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(ir); 689 reader.setParser(parser); 690 reader.parse(); 566 691 progressMonitor.worked(1); 567 692 … … 579 704 } catch(IllegalDataException e) { 580 705 throw e; 581 } catch( ParserConfigurationException e) {706 } catch(OsmParsingException e) { 582 707 throw new IllegalDataException(e.getMessage(), e); 583 } catch (SAXParseException e) { 584 throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLineNumber(), e.getColumnNumber()) + e.getMessage(), e); 585 } catch(SAXException e) { 586 throw new IllegalDataException(e.getMessage(), e); 708 } catch(XMLStreamException e) { 709 String msg = e.getMessage(); 710 Pattern p = Pattern.compile("Message: (.+)"); 711 Matcher m = p.matcher(msg); 712 if (m.find()) { 713 msg = m.group(1); 714 } 715 if (e.getLocation() != null) { 716 throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()) + msg, e); 717 } else { 718 throw new IllegalDataException(msg, e); 719 } 587 720 } catch(Exception e) { 588 721 throw new IllegalDataException(e);
Note:
See TracChangeset
for help on using the changeset viewer.