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

Last change on this file since 8848 was 8846, checked in by Don-vip, 9 years ago

sonar - fb-contrib - minor performance improvements:

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