source: josm/trunk/src/org/openstreetmap/josm/io/OsmWriter.java@ 1071

Last change on this file since 1071 was 1071, checked in by framm, 16 years ago

Support for changeset uploads in 0.6. Error handling is not fully done but basics are working. Full changeset upload is now the default if version is 0.6; set osm-server.atomic-upload=false in your configuration file to go back to individual object upload.

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.io;
3
4import java.io.PrintWriter;
5import java.util.HashMap;
6import java.util.Map.Entry;
7
8import org.openstreetmap.josm.Main;
9import org.openstreetmap.josm.data.osm.DataSet;
10import org.openstreetmap.josm.data.osm.DataSource;
11import org.openstreetmap.josm.data.osm.Relation;
12import org.openstreetmap.josm.data.osm.RelationMember;
13import org.openstreetmap.josm.data.osm.Node;
14import org.openstreetmap.josm.data.osm.OsmPrimitive;
15import org.openstreetmap.josm.data.osm.Changeset;
16import org.openstreetmap.josm.data.osm.Way;
17import org.openstreetmap.josm.data.osm.visitor.Visitor;
18
19/**
20 * Save the dataset into a stream as osm intern xml format. This is not using any
21 * xml library for storing.
22 * @author imi
23 */
24public class OsmWriter extends XmlWriter implements Visitor {
25
26 /**
27 * The counter for new created objects. Starting at -1 and goes down.
28 */
29 private long newIdCounter = -1;
30 /**
31 * All newly created ids and their primitive that uses it. This is a back reference
32 * map to allow references to use the correnct primitives.
33 */
34 public HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
35
36 private final boolean osmConform;
37 private final Changeset changeset;
38
39 public abstract static class Osm implements OsmWriterInterface {
40 public void header(PrintWriter out) {
41 out.print("<osm version='");
42 out.print(Main.pref.get("osm-server.version", "0.5"));
43 out.println("' generator='JOSM'>");
44 }
45 public void footer(PrintWriter out) {
46 out.println("</osm>");
47 }
48 }
49
50 // simple helper to write the object's class to the out stream
51 private Visitor typeWriteVisitor = new Visitor() {
52 public void visit(Node n) { out.print("node"); }
53 public void visit(Way w) { out.print("way"); }
54 public void visit(Relation e) { out.print("relation"); }
55 };
56
57 /**
58 * An output writer for function output that writes everything of the given dataset into
59 * the xml
60 */
61 public static final class All extends Osm {
62 private final DataSet ds;
63 private final boolean osmConform;
64
65 /**
66 * Construct an writer function
67 * @param osmConform <code>true</code>, if the xml should be 100% osm conform. In this
68 * case, not all information can be retrieved later (as example, modified state
69 * is lost and id's remain 0 instead of decrementing from -1)
70 */
71 public All(DataSet ds, boolean osmConform) {
72 this.ds = ds;
73 this.osmConform = osmConform;
74 }
75
76 public void write(PrintWriter out) {
77 Visitor writer = new OsmWriter(out, osmConform, null);
78 for (Node n : ds.nodes)
79 if (shouldWrite(n))
80 writer.visit(n);
81 for (Way w : ds.ways)
82 if (shouldWrite(w))
83 writer.visit(w);
84 for (Relation e : ds.relations)
85 if (shouldWrite(e))
86 writer.visit(e);
87 }
88
89 private boolean shouldWrite(OsmPrimitive osm) {
90 return osm.id != 0 || !osm.deleted;
91 }
92
93 @Override public void header(PrintWriter out) {
94 super.header(out);
95 for (DataSource s : ds.dataSources) {
96 // TODO: remove <bound> output after a grace period (1st October 08)
97 out.print(" <bound note='this tag is deprecated and only provided for backward compatiblity' box='"+
98 s.bounds.min.lat()+","+
99 s.bounds.min.lon()+","+
100 s.bounds.max.lat()+","+
101 s.bounds.max.lon()+"' ");
102 out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
103 out.print(" <bounds minlat='" +
104 s.bounds.min.lat()+"' minlon='"+
105 s.bounds.min.lon()+"' maxlat='"+
106 s.bounds.max.lat()+"' maxlon='"+
107 s.bounds.max.lon()+"' ");
108 out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
109 }
110 }
111 }
112
113 /**
114 * An output writer for functino output that writes only one specific primitive into
115 * the xml
116 */
117 public static final class Single extends Osm {
118 private final OsmPrimitive osm;
119 private final boolean osmConform;
120 private final Changeset changeset;
121
122 public Single(OsmPrimitive osm, boolean osmConform, Changeset changeset) {
123 this.osm = osm;
124 this.osmConform = osmConform;
125 this.changeset = changeset;
126 }
127
128 public void write(PrintWriter out) {
129 osm.visit(new OsmWriter(out, osmConform, changeset));
130 }
131 }
132
133 public OsmWriter(PrintWriter out, boolean osmConform, Changeset changeset) {
134 super(out);
135 this.osmConform = osmConform;
136 this.changeset = changeset;
137 }
138
139 public void visit(Node n) {
140 if (n.incomplete) return;
141 addCommon(n, "node");
142 out.print(" lat='"+n.coor.lat()+"' lon='"+n.coor.lon()+"'");
143 addTags(n, "node", true);
144 }
145
146 public void visit(Way w) {
147 if (w.incomplete) return;
148 addCommon(w, "way");
149 out.println(">");
150 for (Node n : w.nodes)
151 out.println(" <nd ref='"+getUsedId(n)+"' />");
152 addTags(w, "way", false);
153 }
154
155 public void visit(Relation e) {
156 if (e.incomplete) return;
157 addCommon(e, "relation");
158 out.println(">");
159 for (RelationMember em : e.members) {
160 out.print(" <member type='");
161 em.member.visit(typeWriteVisitor);
162 out.println("' ref='"+getUsedId(em.member)+"' role='" +
163 XmlWriter.encode(em.role) + "' />");
164 }
165 addTags(e, "relation", false);
166 }
167
168
169 /**
170 * Return the id for the given osm primitive (may access the usedId map)
171 */
172 private long getUsedId(OsmPrimitive osm) {
173 if (osm.id != 0)
174 return osm.id;
175 if (usedNewIds.containsKey(osm))
176 return usedNewIds.get(osm);
177 usedNewIds.put(osm, newIdCounter);
178 return osmConform ? 0 : newIdCounter--;
179 }
180
181 private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
182 if (osm.keys != null) {
183 if (tagOpen)
184 out.println(">");
185 for (Entry<String, String> e : osm.keys.entrySet())
186 out.println(" <tag k='"+ XmlWriter.encode(e.getKey()) +
187 "' v='"+XmlWriter.encode(e.getValue())+ "' />");
188 out.println(" </" + tagname + ">");
189 } else if (tagOpen)
190 out.println(" />");
191 else
192 out.println(" </" + tagname + ">");
193 }
194
195 /**
196 * Add the common part as the form of the tag as well as the XML attributes
197 * id, action, user, and visible.
198 */
199 private void addCommon(OsmPrimitive osm, String tagname) {
200 out.print(" <"+tagname+" id='"+getUsedId(osm)+"'");
201 if (!osmConform) {
202 String action = null;
203 if (osm.deleted)
204 action = "delete";
205 else if (osm.modified)
206 action = "modify";
207 if (action != null)
208 out.print(" action='"+action+"'");
209 }
210 if (osm.timestamp != null) {
211 out.print(" timestamp='"+osm.timestamp+"'");
212 }
213 // user and visible added with 0.4 API
214 if (osm.user != null) {
215 out.print(" user='"+XmlWriter.encode(osm.user.name)+"'");
216 }
217 out.print(" visible='"+osm.visible+"'");
218 if (osm.version != -1)
219 out.print(" version='"+osm.version+"'");
220 if (this.changeset != null && this.changeset.id != 0)
221 out.print(" changeset='"+this.changeset.id+"'" );
222 }
223}
Note: See TracBrowser for help on using the repository browser.