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

Last change on this file since 3226 was 3012, checked in by jttt, 14 years ago

Save primitives to .osm file sorted

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