Index: src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveAction.java	(revision 48)
+++ src/org/openstreetmap/josm/actions/SaveAction.java	(revision 49)
@@ -54,5 +54,5 @@
 			FileWriter fileWriter;
 			if (fn.endsWith(".gpx"))
-				new GpxWriter(fileWriter = new FileWriter(file)).output();
+				new GpxWriter(fileWriter = new FileWriter(file), Main.main.ds).output();
 			else if (fn.endsWith(".xml") || fn.endsWith(".osm"))
 				new OsmWriter(fileWriter = new FileWriter(file), Main.main.ds).output();
Index: src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxReader.java	(revision 48)
+++ src/org/openstreetmap/josm/io/GpxReader.java	(revision 49)
@@ -2,6 +2,6 @@
 
 import static org.openstreetmap.josm.io.GpxWriter.GPX;
+import static org.openstreetmap.josm.io.GpxWriter.JOSM;
 import static org.openstreetmap.josm.io.GpxWriter.OSM;
-import static org.openstreetmap.josm.io.GpxWriter.JOSM;
 
 import java.io.IOException;
@@ -33,4 +33,13 @@
 	 */
 	public Reader source;
+	/**
+	 * Mapper to find new created objects that occoure more than once.
+	 */
+	private HashMap<Long, OsmPrimitive> newCreatedPrimitives = new HashMap<Long, OsmPrimitive>();
+	/**
+	 * Either set to true or false, depending whether the JOSM namespace declaration 
+	 * was found.
+	 */
+	private boolean mergeNodes = false;
 
 	/**
@@ -49,4 +58,5 @@
 			final SAXBuilder builder = new SAXBuilder();
 			Element root = builder.build(source).getRootElement();
+			mergeNodes = !root.getAdditionalNamespaces().contains(JOSM);
 			return parseDataSet(root);
 		} catch (NullPointerException npe) {
@@ -78,4 +88,5 @@
 				parseKeyValueTag(data, child);
 		}
+		data = (Node)getNewIfSeenBefore(data);
 		return data;
 	}
@@ -89,11 +100,18 @@
 		DataSet data = new DataSet();
 		// read waypoints not contained in tracks or areas
-		for (Object o : e.getChildren("wpt", GPX))
-			addNode(data, parseWaypoint((Element)o));
+		for (Object o : e.getChildren("wpt", GPX)) {
+			Node node = parseWaypoint((Element)o);
+			addNode(data, node);
+		}
 	
 		// read tracks (and line segments)
 		for (Object trackElement : e.getChildren("trk", GPX))
 			parseTrack((Element)trackElement, data);
-	
+
+		// reset new created ids to zero
+		for (OsmPrimitive osm : data.allPrimitives())
+			if (osm.id < 0)
+				osm.id = 0;
+		
 		return data;
 	}
@@ -116,6 +134,5 @@
 				Node start = null;
 				for (Object w : child.getChildren("trkpt", GPX)) {
-					Node node = parseWaypoint((Element)w);
-					node = addNode(ds, node);
+					Node node = addNode(ds, parseWaypoint((Element)w));
 					if (start == null)
 						start = node;
@@ -123,4 +140,5 @@
 						LineSegment lineSegment = new LineSegment(start, node);
 						parseKeyValueExtensions(lineSegment, child.getChild("extensions", GPX));
+						lineSegment = (LineSegment)getNewIfSeenBefore(lineSegment);
 						track.segments.add(lineSegment);
 						start = node;
@@ -136,17 +154,14 @@
 				parseKeyValueTag(track, child);
 		}
+		track = (Track)getNewIfSeenBefore(track);
 		ds.lineSegments.addAll(track.segments);
 		if (!realLineSegment)
 			ds.tracks.add(track);
 	}
-	
 
 	/**
 	 * Adds the node to allNodes if it is not already listed. Does respect the
-	 * preference setting "mergeNodes". Return the node in the list that correspond
+	 * setting "mergeNodes". Return the node in the list that correspond
 	 * to the node in the list (either the new added or the old found).
-	 * 
-	 * If reading raw gps data, mergeNodes are always on (To save memory. You
-	 * can't edit raw gps nodes anyway.)
 	 * 
 	 * @param data The DataSet to add the node to.
@@ -155,9 +170,21 @@
 	 */
 	private Node addNode(DataSet data, Node node) {
-		for (Node n : data.nodes)
-			if (node.coor.equalsLatLon(n.coor))
-				return n;
+		if (mergeNodes)
+			for (Node n : data.nodes)
+				if (node.coor.equalsLatLon(n.coor))
+					return n;
 		data.nodes.add(node);
 		return node;
+	}
+	
+
+	/**
+	 * @return Either the parameter or an index from the newCreatedPrimitives map
+	 * 		with the id seen before.
+	 */
+	private OsmPrimitive getNewIfSeenBefore(OsmPrimitive osm) {
+		if (newCreatedPrimitives.containsKey(osm.id))
+			return newCreatedPrimitives.get(osm.id);
+		return osm;
 	}
 
@@ -189,4 +216,6 @@
 			if (idElement != null)
 				osm.id = Long.parseLong(idElement.getText());
+			if (osm.id < 0 && !newCreatedPrimitives.containsKey(osm.id))
+				newCreatedPrimitives.put(osm.id, osm);
 			osm.modified = e.getChild("modified", JOSM) != null;
 			osm.setDeleted(e.getChild("deleted", JOSM) != null);
Index: src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxWriter.java	(revision 48)
+++ src/org/openstreetmap/josm/io/GpxWriter.java	(revision 49)
@@ -3,4 +3,5 @@
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -14,5 +15,5 @@
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
-import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -50,4 +51,19 @@
 	 */
 	private Writer out;
+	/**
+	 * The dataset beeing processed.
+	 */
+	private DataSet ds;
+	/**
+	 * Map all new primitives to the element which hold them. After inserting everything,
+	 * the writer sets ids to every element that was in the list and had more than one
+	 * element using it. 
+	 */
+	private HashMap<OsmPrimitive, Collection<Element>> usedNewPrimitives = new HashMap<OsmPrimitive, Collection<Element>>();
+	/**
+	 * The counter for new created objects used more than once.
+	 * Starting at -1 and goes down.
+	 */
+	private long newIdCounter = -1;
 	
 	/**
@@ -57,6 +73,7 @@
 	 * @param out The Writer to store the result data in.
 	 */
-	public GpxWriter(Writer out) {
+	public GpxWriter(Writer out, DataSet ds) {
 		this.out = out;
+		this.ds = ds;
 	}
 
@@ -86,10 +103,12 @@
 		e.setAttribute("creator", "JOSM");
 		// for getting all unreferenced waypoints in the wpt-list
-		LinkedList<Node> unrefNodes = new LinkedList<Node>(Main.main.ds.nodes);
+		LinkedList<Node> unrefNodes = new LinkedList<Node>(ds.nodes);
 		// for getting all unreferenced line segments
-		LinkedList<LineSegment> unrefLs = new LinkedList<LineSegment>(Main.main.ds.lineSegments);
+		LinkedList<LineSegment> unrefLs = new LinkedList<LineSegment>(ds.lineSegments);
 
 		// tracks
-		for (Track t : Main.main.ds.tracks) {
+		for (Track t : ds.tracks) {
+			if (t.isDeleted() && t.id == 0)
+				continue;
 			Element tElem = new Element("trk", GPX);
 			HashMap<Key, String> keys = null;
@@ -119,4 +138,6 @@
 		// encode pending line segments as tracks
 		for (LineSegment ls : unrefLs) {
+			if (ls.isDeleted() && ls.id == 0)
+				continue;
 			Element t = new Element("trk", GPX);
 			t.getChildren().add(parseLineSegment(ls));
@@ -130,6 +151,22 @@
 
 		// waypoints (missing nodes)
-		for (Node n : unrefNodes)
+		for (Node n : unrefNodes) {
+			if (n.isDeleted() && n.id == 0)
+				continue;
 			e.getChildren().add(parseWaypoint(n, "wpt"));
+		}
+
+		// link all ids used more than once
+		for (Entry<OsmPrimitive, Collection<Element>> entry : usedNewPrimitives.entrySet()) {
+			if (entry.getValue().size() > 1) {
+				long id = newIdCounter--;
+				for (Element element : entry.getValue()) {
+					Element ext = element.getChild("extensions", GPX);
+					if (ext == null)
+						element.getChildren().add(ext = new Element("extensions", GPX));
+					ext.getChildren().add(new Element("uid", JOSM).setText(""+id));
+				}
+			}
+		}
 
 		return e;
@@ -242,9 +279,5 @@
 	@SuppressWarnings("unchecked")
 	private void addPropertyExtensions(Element e, Map<Key, String> keys, OsmPrimitive osm) {
-		if ((keys == null || keys.isEmpty()) && osm.id == 0 && !osm.modified && !osm.isDeleted() && !osm.modifiedProperties)
-			return;
-		Element extensions = e.getChild("extensions", GPX);
-		if (extensions == null)
-			e.getChildren().add(extensions = new Element("extensions", GPX));
+		LinkedList<Element> extensions = new LinkedList<Element>();
 		if (keys != null && !keys.isEmpty()) {
 			for (Entry<Key, String> prop : keys.entrySet()) {
@@ -252,24 +285,39 @@
 				propElement.setAttribute("key", prop.getKey().name);
 				propElement.setAttribute("value", prop.getValue());
-				extensions.getChildren().add(propElement);
+				extensions.add(propElement);
 			}
 		}
+		
 		if (osm.id != 0) {
 			Element propElement = new Element("uid", JOSM);
 			propElement.setText(""+osm.id);
-			extensions.getChildren().add(propElement);
+			extensions.add(propElement);
+		} else {
+			Collection<Element> l = usedNewPrimitives.get(osm);
+			if (l == null)
+				l = new LinkedList<Element>();
+			l.add(e);
+			usedNewPrimitives.put(osm, l);
 		}
 		if (osm.modified) {
 			Element modElement = new Element("modified", JOSM);
-			extensions.getChildren().add(modElement);
+			extensions.add(modElement);
 		}
 		if (osm.isDeleted()) {
 			Element modElement = new Element("deleted", JOSM);
-			extensions.getChildren().add(modElement);
+			extensions.add(modElement);
 		}
 		if (osm.modifiedProperties) {
 			Element modElement = new Element("modifiedProperties", JOSM);
-			extensions.getChildren().add(modElement);
-		}
+			extensions.add(modElement);
+		}
+		
+		if (extensions.isEmpty())
+			return;
+
+		Element ext = e.getChild("extensions", GPX);
+		if (ext == null)
+			e.getChildren().add(ext = new Element("extensions", GPX));
+		ext.getChildren().addAll(extensions);
 	}
 }
Index: src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmWriter.java	(revision 48)
+++ src/org/openstreetmap/josm/io/OsmWriter.java	(revision 49)
@@ -4,4 +4,5 @@
 import java.io.Writer;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -39,4 +40,9 @@
 	 */
 	private long newIdCounter = -1;
+	/**
+	 * All newly created ids and their primitive that uses it. This is a back reference
+	 * map to allow references to use the correnct primitives.
+	 */
+	private HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
 
 	/**
@@ -72,5 +78,5 @@
 		Collection<Element> allDeleted = deleted.getChildren();
 		for (OsmPrimitive osm : ds.allPrimitives()) {
-			if (osm.isDeleted()) {
+			if (osm.isDeleted() && osm.id != 0) {
 				osm.visit(this);
 				allDeleted.add(element);
@@ -103,6 +109,8 @@
 	private void addProperties(Element e, OsmPrimitive osm) {
 		long id = osm.id;
-		if (id == 0)
+		if (id == 0) {
 			id = newIdCounter--;
+			usedNewIds.put(osm, id);
+		}
 		e.setAttribute("uid", ""+id);
 		if (osm.keys != null)
@@ -127,6 +135,13 @@
 		element = new Element("segment");
 		addProperties(element, ls);
-		element.setAttribute("from", ""+ls.start.id);
-		element.setAttribute("to", ""+ls.end.id);
+		element.setAttribute("from", ""+getUsedId(ls.start));
+		element.setAttribute("to", ""+getUsedId(ls.end));
+	}
+
+	/**
+	 * Return the id for the given osm primitive (may access the usedId map)
+	 */
+	private Long getUsedId(OsmPrimitive osm) {
+		return osm.id == 0 ? usedNewIds.get(osm) : osm.id;
 	}
 
@@ -139,5 +154,5 @@
 		addProperties(element, t);
 		for (LineSegment ls : t.segments)
-			element.getChildren().add(new Element("segment").setAttribute("uid", ""+ls.id));
+			element.getChildren().add(new Element("segment").setAttribute("uid", ""+getUsedId(ls)));
 	}
 
@@ -147,3 +162,2 @@
 	}
 }
-
