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

Last change on this file since 5299 was 5025, checked in by Don-vip, 12 years ago

see #4043 - Have an 'upload prohibited' flag in .osm files

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.PrintWriter;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.Comparator;
11import java.util.List;
12import java.util.Map.Entry;
13
14import org.openstreetmap.josm.data.coor.CoordinateFormat;
15import org.openstreetmap.josm.data.osm.Changeset;
16import org.openstreetmap.josm.data.osm.DataSet;
17import org.openstreetmap.josm.data.osm.DataSource;
18import org.openstreetmap.josm.data.osm.INode;
19import org.openstreetmap.josm.data.osm.IPrimitive;
20import org.openstreetmap.josm.data.osm.IRelation;
21import org.openstreetmap.josm.data.osm.IWay;
22import org.openstreetmap.josm.data.osm.Node;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.Relation;
25import org.openstreetmap.josm.data.osm.Tagged;
26import org.openstreetmap.josm.data.osm.Way;
27import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
28import org.openstreetmap.josm.gui.layer.OsmDataLayer;
29import org.openstreetmap.josm.tools.DateUtils;
30
31/**
32 * Save the dataset into a stream as osm intern xml format. This is not using any
33 * xml library for storing.
34 * @author imi
35 */
36public class OsmWriter extends XmlWriter implements PrimitiveVisitor {
37
38 public static final String DEFAULT_API_VERSION = "0.6";
39
40 private boolean osmConform;
41 private boolean withBody = true;
42 private String version;
43 private Changeset changeset;
44
45 /**
46 * Do not call this directly. Use OsmWriterFactory instead.
47 */
48 protected OsmWriter(PrintWriter out, boolean osmConform, String version) {
49 super(out);
50 this.osmConform = osmConform;
51 this.version = (version == null ? DEFAULT_API_VERSION : version);
52 }
53
54 public void setWithBody(boolean wb) {
55 this.withBody = wb;
56 }
57 public void setChangeset(Changeset cs) {
58 this.changeset = cs;
59 }
60 public void setVersion(String v) {
61 this.version = v;
62 }
63
64 public void header() {
65 header(null);
66 }
67 public void header(Boolean upload) {
68 out.println("<?xml version='1.0' encoding='UTF-8'?>");
69 out.print("<osm version='");
70 out.print(version);
71 if (upload != null) {
72 out.print("' upload='");
73 out.print(upload);
74 }
75 out.println("' generator='JOSM'>");
76 }
77 public void footer() {
78 out.println("</osm>");
79 }
80
81 protected static final Comparator<OsmPrimitive> byIdComparator = new Comparator<OsmPrimitive>() {
82 @Override public int compare(OsmPrimitive o1, OsmPrimitive o2) {
83 return (o1.getUniqueId()<o2.getUniqueId() ? -1 : (o1.getUniqueId()==o2.getUniqueId() ? 0 : 1));
84 }
85 };
86
87 protected Collection<OsmPrimitive> sortById(Collection<? extends OsmPrimitive> primitives) {
88 List<OsmPrimitive> result = new ArrayList<OsmPrimitive>(primitives.size());
89 result.addAll(primitives);
90 Collections.sort(result, byIdComparator);
91 return result;
92 }
93
94 public void writeLayer(OsmDataLayer layer) {
95 header(!layer.isUploadDiscouraged());
96 writeDataSources(layer.data);
97 writeContent(layer.data);
98 footer();
99 }
100
101 public void writeContent(DataSet ds) {
102 for (OsmPrimitive n : sortById(ds.getNodes())) {
103 if (shouldWrite(n)) {
104 visit((Node)n);
105 }
106 }
107 for (OsmPrimitive w : sortById(ds.getWays())) {
108 if (shouldWrite(w)) {
109 visit((Way)w);
110 }
111 }
112 for (OsmPrimitive e: sortById(ds.getRelations())) {
113 if (shouldWrite(e)) {
114 visit((Relation)e);
115 }
116 }
117 }
118
119 protected boolean shouldWrite(OsmPrimitive osm) {
120 return !osm.isNewOrUndeleted() || !osm.isDeleted();
121 }
122
123 public void writeDataSources(DataSet ds) {
124 for (DataSource s : ds.dataSources) {
125 out.println(" <bounds minlat='"
126 + s.bounds.getMin().lat()+"' minlon='"
127 + s.bounds.getMin().lon()+"' maxlat='"
128 + s.bounds.getMax().lat()+"' maxlon='"
129 + s.bounds.getMax().lon()
130 +"' origin='"+XmlWriter.encode(s.origin)+"' />");
131 }
132 }
133
134 @Override
135 public void visit(INode n) {
136 if (n.isIncomplete()) return;
137 addCommon(n, "node");
138 out.print(" lat='"+n.getCoor().lat()+"' lon='"+n.getCoor().lon()+"'");
139 if (!withBody) {
140 out.println("/>");
141 } else {
142 addTags(n, "node", true);
143 }
144 }
145
146 @Override
147 public void visit(IWay w) {
148 if (w.isIncomplete()) return;
149 addCommon(w, "way");
150 if (!withBody) {
151 out.println("/>");
152 } else {
153 out.println(">");
154 for (int i=0; i<w.getNodesCount(); ++i) {
155 out.println(" <nd ref='"+w.getNodeId(i) +"' />");
156 }
157 addTags(w, "way", false);
158 }
159 }
160
161 @Override
162 public void visit(IRelation e) {
163 if (e.isIncomplete()) return;
164 addCommon(e, "relation");
165 if (!withBody) {
166 out.println("/>");
167 } else {
168 out.println(">");
169 for (int i=0; i<e.getMembersCount(); ++i) {
170 out.print(" <member type='");
171 out.print(e.getMemberType(i).getAPIName());
172 out.println("' ref='"+e.getMemberId(i)+"' role='" +
173 XmlWriter.encode(e.getRole(i)) + "' />");
174 }
175 addTags(e, "relation", false);
176 }
177 }
178
179 public void visit(Changeset cs) {
180 out.print(" <changeset ");
181 out.print(" id='"+cs.getId()+"'");
182 if (cs.getUser() != null) {
183 out.print(" user='"+cs.getUser().getName() +"'");
184 out.print(" uid='"+cs.getUser().getId() +"'");
185 }
186 if (cs.getCreatedAt() != null) {
187 out.print(" created_at='"+DateUtils.fromDate(cs.getCreatedAt()) +"'");
188 }
189 if (cs.getClosedAt() != null) {
190 out.print(" closed_at='"+DateUtils.fromDate(cs.getClosedAt()) +"'");
191 }
192 out.print(" open='"+ (cs.isOpen() ? "true" : "false") +"'");
193 if (cs.getMin() != null) {
194 out.print(" min_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
195 out.print(" min_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
196 }
197 if (cs.getMax() != null) {
198 out.print(" max_lon='"+ cs.getMin().lonToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
199 out.print(" max_lat='"+ cs.getMin().latToString(CoordinateFormat.DECIMAL_DEGREES) +"'");
200 }
201 out.println(">");
202 addTags(cs, "changeset", false); // also writes closing </changeset>
203 }
204
205 protected static final Comparator<Entry<String, String>> byKeyComparator = new Comparator<Entry<String,String>>() {
206 @Override public int compare(Entry<String, String> o1, Entry<String, String> o2) {
207 return o1.getKey().compareTo(o2.getKey());
208 }
209 };
210
211 protected void addTags(Tagged osm, String tagname, boolean tagOpen) {
212 if (osm.hasKeys()) {
213 if (tagOpen) {
214 out.println(">");
215 }
216 List<Entry<String, String>> entries = new ArrayList<Entry<String,String>>(osm.getKeys().entrySet());
217 Collections.sort(entries, byKeyComparator);
218 for (Entry<String, String> e : entries) {
219 if ((osm instanceof Changeset) || !("created_by".equals(e.getKey()))) {
220 out.println(" <tag k='"+ XmlWriter.encode(e.getKey()) +
221 "' v='"+XmlWriter.encode(e.getValue())+ "' />");
222 }
223 }
224 out.println(" </" + tagname + ">");
225 } else if (tagOpen) {
226 out.println(" />");
227 } else {
228 out.println(" </" + tagname + ">");
229 }
230 }
231
232 /**
233 * Add the common part as the form of the tag as well as the XML attributes
234 * id, action, user, and visible.
235 */
236 protected void addCommon(IPrimitive osm, String tagname) {
237 out.print(" <"+tagname);
238 if (osm.getUniqueId() != 0) {
239 out.print(" id='"+ osm.getUniqueId()+"'");
240 } else
241 throw new IllegalStateException(tr("Unexpected id 0 for osm primitive found"));
242 if (!osmConform) {
243 String action = null;
244 if (osm.isDeleted()) {
245 action = "delete";
246 } else if (osm.isModified()) {
247 action = "modify";
248 }
249 if (action != null) {
250 out.print(" action='"+action+"'");
251 }
252 }
253 if (!osm.isTimestampEmpty()) {
254 out.print(" timestamp='"+DateUtils.fromDate(osm.getTimestamp())+"'");
255 }
256 // user and visible added with 0.4 API
257 if (osm.getUser() != null) {
258 if(osm.getUser().isLocalUser()) {
259 out.print(" user='"+XmlWriter.encode(osm.getUser().getName())+"'");
260 } else if (osm.getUser().isOsmUser()) {
261 // uid added with 0.6
262 out.print(" uid='"+ osm.getUser().getId()+"'");
263 out.print(" user='"+XmlWriter.encode(osm.getUser().getName())+"'");
264 }
265 }
266 out.print(" visible='"+osm.isVisible()+"'");
267 if (osm.getVersion() != 0) {
268 out.print(" version='"+osm.getVersion()+"'");
269 }
270 if (this.changeset != null && this.changeset.getId() != 0) {
271 out.print(" changeset='"+this.changeset.getId()+"'" );
272 } else if (osm.getChangesetId() > 0 && !osm.isNew()) {
273 out.print(" changeset='"+osm.getChangesetId()+"'" );
274 }
275 }
276
277 public void close() {
278 out.close();
279 }
280
281 @Override
282 public void flush() {
283 out.flush();
284 }
285}
Note: See TracBrowser for help on using the repository browser.