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

Last change on this file since 1023 was 769, checked in by framm, 16 years ago
  • add support for <bounds> tag in .osm files using four attributes minlat,maxlat,minlon,maxlon. old <bound> still supported for a transition period. fixes #1112.
  • 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 private 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 private 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
182 private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
183 if (osm.keys != null) {
184 if (tagOpen)
185 out.println(">");
186 for (Entry<String, String> e : osm.keys.entrySet())
187 out.println(" <tag k='"+ XmlWriter.encode(e.getKey()) +
188 "' v='"+XmlWriter.encode(e.getValue())+ "' />");
189 out.println(" </" + tagname + ">");
190 } else if (tagOpen)
191 out.println(" />");
192 else
193 out.println(" </" + tagname + ">");
194 }
195
196 /**
197 * Add the common part as the form of the tag as well as the XML attributes
198 * id, action, user, and visible.
199 */
200 private void addCommon(OsmPrimitive osm, String tagname) {
201 out.print(" <"+tagname+" id='"+getUsedId(osm)+"'");
202 if (!osmConform) {
203 String action = null;
204 if (osm.deleted)
205 action = "delete";
206 else if (osm.modified)
207 action = "modify";
208 if (action != null)
209 out.print(" action='"+action+"'");
210 }
211 if (osm.timestamp != null) {
212 out.print(" timestamp='"+osm.timestamp+"'");
213 }
214 // user and visible added with 0.4 API
215 if (osm.user != null) {
216 out.print(" user='"+XmlWriter.encode(osm.user.name)+"'");
217 }
218 out.print(" visible='"+osm.visible+"'");
219 if( osm.version != -1 )
220 out.print( " old_version='"+osm.version+"'");
221 if( this.changeset != null && this.changeset.id != 0)
222 out.print( " changeset='"+this.changeset.id+"'" );
223 }
224}
Note: See TracBrowser for help on using the repository browser.