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

Last change on this file since 1499 was 1499, checked in by stoecker, 15 years ago

close #2302 - patch by jttt - optimizations and encapsulation

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