Changeset 15496 in josm for trunk/src/org/openstreetmap/josm/io
- Timestamp:
- 2019-11-02T15:11:34+01:00 (5 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/io
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/GpxReader.java
r14456 r15496 19 19 import org.openstreetmap.josm.data.Bounds; 20 20 import org.openstreetmap.josm.data.coor.LatLon; 21 import org.openstreetmap.josm.data.gpx.Extensions;22 21 import org.openstreetmap.josm.data.gpx.GpxConstants; 23 22 import org.openstreetmap.josm.data.gpx.GpxData; 23 import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace; 24 import org.openstreetmap.josm.data.gpx.GpxExtensionCollection; 24 25 import org.openstreetmap.josm.data.gpx.GpxLink; 25 26 import org.openstreetmap.josm.data.gpx.GpxRoute; 26 import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack; 27 import org.openstreetmap.josm.data.gpx.GpxTrack; 28 import org.openstreetmap.josm.data.gpx.GpxTrackSegment; 29 import org.openstreetmap.josm.data.gpx.IGpxTrackSegment; 27 30 import org.openstreetmap.josm.data.gpx.WayPoint; 28 31 import org.openstreetmap.josm.tools.Logging; … … 68 71 69 72 private GpxData data; 70 private Collection< Collection<WayPoint>> currentTrack;73 private Collection<IGpxTrackSegment> currentTrack; 71 74 private Map<String, Object> currentTrackAttr; 72 75 private Collection<WayPoint> currentTrackSeg; … … 77 80 78 81 private GpxLink currentLink; 79 private Extensions currentExtensions; 82 private GpxExtensionCollection currentExtensionCollection; 83 private GpxExtensionCollection currentTrackExtensionCollection; 80 84 private Stack<State> states; 81 85 private final Stack<String> elements = new Stack<>(); … … 89 93 accumulator = new StringBuilder(); 90 94 states = new Stack<>(); 91 data = new GpxData(); 95 data = new GpxData(true); 96 currentExtensionCollection = new GpxExtensionCollection(); 97 currentTrackExtensionCollection = new GpxExtensionCollection(); 98 } 99 100 @Override 101 public void startPrefixMapping(String prefix, String uri) throws SAXException { 102 data.getNamespaces().add(new XMLNamespace(prefix, uri)); 92 103 } 93 104 … … 134 145 version = "1.1"; 135 146 } 147 String schemaLocation = atts.getValue(GpxConstants.XML_URI_XSD, "schemaLocation"); 148 if (schemaLocation != null) { 149 String[] schemaLocations = schemaLocation.split(" "); 150 for (int i = 0; i < schemaLocations.length - 1; i += 2) { 151 final String schemaURI = schemaLocations[i]; 152 final String schemaXSD = schemaLocations[i + 1]; 153 data.getNamespaces().stream().filter(xml -> xml.getURI().equals(schemaURI)).forEach(xml -> { 154 xml.setLocation(schemaXSD); 155 }); 156 } 157 } 136 158 break; 137 159 case GPX: … … 160 182 states.push(currentState); 161 183 currentState = State.EXT; 162 currentExtensions = new Extensions();163 184 break; 164 185 case "gpx": … … 179 200 states.push(currentState); 180 201 currentState = State.EXT; 181 currentExtensions = new Extensions();182 202 break; 183 203 case "copyright": … … 229 249 states.push(currentState); 230 250 currentState = State.EXT; 231 currentExtensions = new Extensions();232 251 break; 233 252 default: // Do nothing … … 235 254 break; 236 255 case TRKSEG: 237 if ("trkpt".equals(localName)) { 256 switch (localName) { 257 case "trkpt": 238 258 states.push(currentState); 239 259 currentState = State.WPT; 240 260 currentWayPoint = new WayPoint(parseLatLon(atts)); 261 break; 262 case "extensions": 263 states.push(currentState); 264 currentState = State.EXT; 265 break; 241 266 } 242 267 break; … … 251 276 states.push(currentState); 252 277 currentState = State.EXT; 253 currentExtensions = new Extensions();254 278 break; 255 279 default: // Do nothing … … 271 295 states.push(currentState); 272 296 currentState = State.EXT; 273 currentExtensions = new Extensions(); 274 break; 275 default: // Do nothing 297 break; 298 default: // Do nothing 299 } 300 break; 301 case EXT: 302 if (states.lastElement() == State.TRK) { 303 currentTrackExtensionCollection.openChild(namespaceURI, qName, atts); 304 } else { 305 currentExtensionCollection.openChild(namespaceURI, qName, atts); 276 306 } 277 307 break; … … 350 380 (currentState == State.GPX && "gpx".equals(localName))) { 351 381 convertUrlToLink(data.attr); 352 if (currentExtensions != null && !currentExtensions.isEmpty()) { 353 data.put(META_EXTENSIONS, currentExtensions); 354 } 382 data.getExtensions().addAll(currentExtensionCollection); 383 currentExtensionCollection.clear(); 355 384 currentState = states.pop(); 356 385 } … … 360 389 break; 361 390 default: 362 //TODO: parse extensions363 391 } 364 392 break; … … 465 493 currentState = states.pop(); 466 494 convertUrlToLink(currentWayPoint.attr); 467 if (currentExtensions != null && !currentExtensions.isEmpty()) { 468 currentWayPoint.put(META_EXTENSIONS, currentExtensions); 469 } 495 currentWayPoint.getExtensions().addAll(currentExtensionCollection); 470 496 data.waypoints.add(currentWayPoint); 497 currentExtensionCollection.clear(); 471 498 break; 472 499 default: // Do nothing … … 476 503 if ("trkseg".equals(localName)) { 477 504 currentState = states.pop(); 478 currentTrack.add(currentTrackSeg); 505 if (!currentTrackSeg.isEmpty()) { 506 GpxTrackSegment seg = new GpxTrackSegment(currentTrackSeg); 507 seg.getExtensions().addAll(currentExtensionCollection); 508 currentTrack.add(seg); 509 } 510 currentExtensionCollection.clear(); 479 511 } 480 512 break; … … 484 516 currentState = states.pop(); 485 517 convertUrlToLink(currentTrackAttr); 486 data.addTrack(new ImmutableGpxTrack(currentTrack, currentTrackAttr)); 518 GpxTrack trk = new GpxTrack(new ArrayList<>(currentTrack), currentTrackAttr); 519 trk.getExtensions().addAll(currentTrackExtensionCollection); 520 data.addTrack(trk); 521 currentTrackExtensionCollection.clear(); 487 522 break; 488 523 case "name": … … 502 537 if ("extensions".equals(localName)) { 503 538 currentState = states.pop(); 504 } else if (JOSM_EXTENSIONS_NAMESPACE_URI.equals(namespaceURI)) { 505 // only interested in extensions written by JOSM 506 currentExtensions.put(localName, accumulator.toString()); 539 } else if (currentExtensionCollection != null) { 540 String acc = accumulator.toString().trim(); 541 if (states.lastElement() == State.TRK) { 542 currentTrackExtensionCollection.closeChild(qName, acc); //a segment inside the track can have an extension too 543 } else { 544 currentExtensionCollection.closeChild(qName, acc); 545 } 507 546 } 508 547 break; … … 520 559 } 521 560 } 561 accumulator.setLength(0); 522 562 } 523 563 … … 526 566 if (!states.empty()) 527 567 throw new SAXException(tr("Parse error: invalid document structure for GPX document.")); 528 Extensions metaExt = (Extensions) data.get(META_EXTENSIONS); 529 if (metaExt != null && "true".equals(metaExt.get("from-server"))) { 530 data.fromServer = true; 531 } 568 569 data.getExtensions().stream("josm", "from-server").findAny().ifPresent(ext -> { 570 data.fromServer = "true".equals(ext.getValue()); 571 }); 572 573 data.getExtensions().stream("josm", "layerPreferences").forEach(prefs -> { 574 prefs.getExtensions().stream("josm", "entry").forEach(prefEntry -> { 575 Object key = prefEntry.get("key"); 576 Object val = prefEntry.get("value"); 577 if (key != null && val != null) { 578 data.getLayerPrefs().put(key.toString(), val.toString()); 579 } 580 }); 581 }); 582 data.endUpdate(); 532 583 gpxData = data; 533 584 } -
trunk/src/org/openstreetmap/josm/io/GpxWriter.java
r14459 r15496 9 9 import java.io.PrintWriter; 10 10 import java.nio.charset.StandardCharsets; 11 import java.util.ArrayList; 11 12 import java.util.Collection; 12 13 import java.util.Date; 13 14 import java.util.List; 14 15 import java.util.Map; 15 import java.util.Map.Entry; 16 import java.util.Objects; 17 import java.util.stream.Collectors; 16 18 17 19 import javax.xml.XMLConstants; … … 19 21 import org.openstreetmap.josm.data.Bounds; 20 22 import org.openstreetmap.josm.data.coor.LatLon; 21 import org.openstreetmap.josm.data.gpx.Extensions;22 23 import org.openstreetmap.josm.data.gpx.GpxConstants; 23 24 import org.openstreetmap.josm.data.gpx.GpxData; 25 import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace; 26 import org.openstreetmap.josm.data.gpx.GpxExtension; 27 import org.openstreetmap.josm.data.gpx.GpxExtensionCollection; 24 28 import org.openstreetmap.josm.data.gpx.GpxLink; 25 29 import org.openstreetmap.josm.data.gpx.GpxRoute; 26 30 import org.openstreetmap.josm.data.gpx.GpxTrack; 27 import org.openstreetmap.josm.data.gpx.GpxTrackSegment; 31 import org.openstreetmap.josm.data.gpx.IGpxTrackSegment; 28 32 import org.openstreetmap.josm.data.gpx.IWithAttributes; 29 33 import org.openstreetmap.josm.data.gpx.WayPoint; … … 55 59 private GpxData data; 56 60 private String indent = ""; 61 private List<String> validprefixes; 57 62 58 63 private static final int WAY_POINT = 0; … … 65 70 */ 66 71 public void write(GpxData data) { 72 write(data, ColorFormat.GPXD, true); 73 } 74 75 /** 76 * Writes the given GPX data. 77 * 78 * @param data The data to write 79 * @param colorFormat determines if colors are saved and which extension is to be used 80 * @param savePrefs whether layer specific preferences are saved 81 */ 82 public void write(GpxData data, ColorFormat colorFormat, boolean savePrefs) { 67 83 this.data = data; 68 // We write JOSM specific meta information into gpx 'extensions' elements. 69 // In particular it is noted whether the gpx data is from the OSM server 70 // (so the rendering of clouds of anonymous TrackPoints can be improved) 71 // and some extra synchronization info for export of AudioMarkers. 72 // It is checked in advance, if any extensions are used, so we know whether 73 // a namespace declaration is necessary. 74 boolean hasExtensions = data.fromServer; 75 if (!hasExtensions) { 76 for (WayPoint wpt : data.waypoints) { 77 Extensions extensions = (Extensions) wpt.get(META_EXTENSIONS); 78 if (extensions != null && !extensions.isEmpty()) { 79 hasExtensions = true; 80 break; 81 } 82 } 83 } 84 85 //Prepare extensions for writing 86 data.beginUpdate(); 87 data.getTracks().forEach(trk -> trk.convertColor(colorFormat)); 88 data.getExtensions().removeAllWithPrefix("josm"); 89 if (data.fromServer) { 90 data.getExtensions().add("josm", "from-server", "true"); 91 } 92 if (savePrefs && !data.getLayerPrefs().isEmpty()) { 93 GpxExtensionCollection layerExts = data.getExtensions().add("josm", "layerPreferences").getExtensions(); 94 data.getLayerPrefs().entrySet() 95 .stream() 96 .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey())) 97 .forEach(entry -> { 98 GpxExtension e = layerExts.add("josm", "entry"); 99 e.put("key", entry.getKey()); 100 e.put("value", entry.getValue()); 101 }); 102 } 103 data.endUpdate(); 104 105 Collection<IWithAttributes> all = new ArrayList<>(); 106 107 all.add(data); 108 all.addAll(data.getWaypoints()); 109 all.addAll(data.getRoutes()); 110 all.addAll(data.getTracks()); 111 all.addAll(data.getTrackSegmentsStream().collect(Collectors.toList())); 112 113 List<XMLNamespace> namespaces = all 114 .stream() 115 .flatMap(w -> w.getExtensions().getPrefixesStream()) 116 .distinct() 117 .map(p -> data.getNamespaces() 118 .stream() 119 .filter(s -> s.getPrefix().equals(p)) 120 .findAny() 121 .orElse(GpxExtension.findNamespace(p))) 122 .filter(Objects::nonNull) 123 .collect(Collectors.toList()); 124 125 validprefixes = namespaces.stream().map(n -> n.getPrefix()).collect(Collectors.toList()); 84 126 85 127 out.println("<?xml version='1.0' encoding='UTF-8'?>"); 86 128 out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\""); 87 out.println((hasExtensions ? String.format(" xmlns:josm=\"%s\"%n", JOSM_EXTENSIONS_NAMESPACE_URI) : "") + 88 " xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\""); 89 out.println(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"); 129 130 String schemaLocations = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"; 131 132 for (XMLNamespace n : namespaces) { 133 if (n.getURI() != null && n.getPrefix() != null && !n.getPrefix().isEmpty()) { 134 out.println(String.format(" xmlns:%s=\"%s\"", n.getPrefix(), n.getURI())); 135 if (n.getLocation() != null) { 136 schemaLocations += " " + n.getURI() + " " + n.getLocation(); 137 } 138 } 139 } 140 141 out.println(" xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\""); 142 out.println(String.format(" xsi:schemaLocation=\"%s\">", schemaLocations)); 90 143 indent = " "; 91 144 writeMetaData(); … … 105 158 gpxLink(link); 106 159 } 107 }108 } else if (META_EXTENSIONS.equals(key)) {109 Extensions extensions = (Extensions) obj.get(key);110 if (extensions != null) {111 gpxExtensions(extensions);112 160 } 113 161 } else { … … 148 196 String[] tmp = data.getString(META_AUTHOR_EMAIL).split("@"); 149 197 if (tmp.length == 2) { 150 inline("email", "id=\"" + tmp[0]+ "\" domain=\""+tmp[1]+'\"');198 inline("email", "id=\"" + encode(tmp[0]) + "\" domain=\"" + encode(tmp[1]) +'\"'); 151 199 } 152 200 } … … 159 207 if (attr.containsKey(META_COPYRIGHT_LICENSE) 160 208 || attr.containsKey(META_COPYRIGHT_YEAR)) { 161 open Att("copyright", "author=\""+ data.get(META_COPYRIGHT_AUTHOR) +'\"');209 openln("copyright", "author=\""+ encode(data.get(META_COPYRIGHT_AUTHOR).toString()) +'\"'); 162 210 if (attr.containsKey(META_COPYRIGHT_YEAR)) { 163 211 simpleTag("year", (String) data.get(META_COPYRIGHT_YEAR)); … … 188 236 } 189 237 190 if (data.fromServer) { 191 openln("extensions"); 192 simpleTag("josm:from-server", "true"); 193 closeln("extensions"); 194 } 195 238 gpxExtensions(data.getExtensions()); 196 239 closeln("metadata"); 197 240 } … … 207 250 openln("rte"); 208 251 writeAttr(rte, RTE_TRK_KEYS); 252 gpxExtensions(rte.getExtensions()); 209 253 for (WayPoint pnt : rte.routePoints) { 210 254 wayPoint(pnt, ROUTE_POINT); … … 218 262 openln("trk"); 219 263 writeAttr(trk, RTE_TRK_KEYS); 220 for (GpxTrackSegment seg : trk.getSegments()) { 264 gpxExtensions(trk.getExtensions()); 265 for (IGpxTrackSegment seg : trk.getSegments()) { 221 266 openln("trkseg"); 267 gpxExtensions(seg.getExtensions()); 222 268 for (WayPoint pnt : seg.getWayPoints()) { 223 269 wayPoint(pnt, TRACK_POINT); … … 234 280 } 235 281 282 private void openln(String tag, String attributes) { 283 open(tag, attributes); 284 out.println(); 285 } 286 236 287 private void open(String tag) { 237 288 out.print(indent + '<' + tag + '>'); … … 239 290 } 240 291 241 private void open Att(String tag, String attributes) {242 out.print ln(indent + '<' + tag +' '+ attributes + '>');292 private void open(String tag, String attributes) { 293 out.print(indent + '<' + tag + (attributes.isEmpty() ? "" : ' ') + attributes + '>'); 243 294 indent += " "; 244 295 } 245 296 246 297 private void inline(String tag, String attributes) { 247 out.println(indent + '<' + tag + ' '+ attributes + "/>");298 out.println(indent + '<' + tag + (attributes.isEmpty() ? "" : ' ') + attributes + "/>"); 248 299 } 249 300 … … 273 324 } 274 325 326 private void simpleTag(String tag, String content, String attributes) { 327 if (content != null && !content.isEmpty()) { 328 open(tag, attributes); 329 out.print(encode(content)); 330 out.println("</" + tag + '>'); 331 indent = indent.substring(2); 332 } 333 } 334 275 335 /** 276 336 * output link … … 279 339 private void gpxLink(GpxLink link) { 280 340 if (link != null) { 281 open Att("link", "href=\"" +link.uri+ '\"');341 openln("link", "href=\"" + encode(link.uri) + '\"'); 282 342 simpleTag("text", link.text); 283 343 simpleTag("type", link.type); … … 309 369 LatLon c = pnt.getCoor(); 310 370 String coordAttr = "lat=\"" + c.lat() + "\" lon=\"" + c.lon() + '\"'; 311 if (pnt.attr.isEmpty()) { 371 if (pnt.attr.isEmpty() && pnt.getExtensions().isEmpty()) { 312 372 inline(type, coordAttr); 313 373 } else { 314 open Att(type, coordAttr);374 openln(type, coordAttr); 315 375 writeAttr(pnt, WPT_KEYS); 376 gpxExtensions(pnt.getExtensions()); 316 377 closeln(type); 317 378 } … … 319 380 } 320 381 321 private void gpxExtensions(Extension s extensions) {322 if ( extensions != null && !extensions.isEmpty()) {382 private void gpxExtensions(GpxExtensionCollection allExtensions) { 383 if (allExtensions.isVisible()) { 323 384 openln("extensions"); 324 for (Entry<String, String> e : extensions.entrySet()) { 325 simpleTag("josm:" + e.getKey(), e.getValue()); 326 } 385 writeExtension(allExtensions); 327 386 closeln("extensions"); 328 387 } 329 388 } 389 390 private void writeExtension(List<GpxExtension> extensions) { 391 for (GpxExtension e : extensions) { 392 if (validprefixes.contains(e.getPrefix()) && e.isVisible()) { 393 // this might lead to loss of an unknown extension *after* the file was saved as .osm, 394 // but otherwise the file is invalid and can't even be parsed by SAX anymore 395 String k = (e.getPrefix().isEmpty() ? "" : e.getPrefix() + ":") + e.getKey(); 396 String attr = String.join(" ", e.getAttributes().entrySet().stream().map(a -> encode(a.getKey()) + "=\"" + encode(a.getValue().toString()) + "\"").sorted().collect(Collectors.toList())); 397 if (e.getValue() == null && e.getExtensions().isEmpty()) { 398 inline(k, attr); 399 } else if (e.getExtensions().isEmpty()) { 400 simpleTag(k, e.getValue(), attr); 401 } else { 402 openln(k, attr); 403 if (e.getValue() != null) { 404 out.print(encode(e.getValue())); 405 } 406 writeExtension(e.getExtensions()); 407 closeln(k); 408 } 409 } 410 } 411 } 330 412 } -
trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java
r15247 r15496 21 21 import org.openstreetmap.josm.data.gpx.GpxConstants; 22 22 import org.openstreetmap.josm.data.gpx.GpxData; 23 import org.openstreetmap.josm.data.gpx. ImmutableGpxTrack;23 import org.openstreetmap.josm.data.gpx.GpxTrack; 24 24 import org.openstreetmap.josm.data.gpx.WayPoint; 25 25 import org.openstreetmap.josm.io.IGpxReader; … … 265 265 } 266 266 currentTrack.add(ps.waypoints); 267 data.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));267 data.tracks.add(new GpxTrack(currentTrack, Collections.<String, Object>emptyMap())); 268 268 269 269 } catch (IllegalDataException e) { -
trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java
r15343 r15496 19 19 import org.openstreetmap.josm.data.gpx.GpxConstants; 20 20 import org.openstreetmap.josm.data.gpx.GpxData; 21 import org.openstreetmap.josm.data.gpx. ImmutableGpxTrack;21 import org.openstreetmap.josm.data.gpx.GpxTrack; 22 22 import org.openstreetmap.josm.data.gpx.WayPoint; 23 23 import org.openstreetmap.josm.io.IGpxReader; … … 115 115 } 116 116 currentTrack.add(waypoints); 117 data.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));117 data.tracks.add(new GpxTrack(currentTrack, Collections.<String, Object>emptyMap())); 118 118 return true; 119 119 } -
trunk/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java
r15404 r15496 82 82 @Override 83 83 public void actionPerformed(ActionEvent e) { 84 SaveAction.getInstance().doSave(layer); 84 SaveAction.getInstance().doSave(layer, true); 85 85 updateEnabledState(); 86 86 }
Note:
See TracChangeset
for help on using the changeset viewer.