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

Last change on this file since 1735 was 1735, checked in by framm, 14 years ago
  • do NOT drop created_by on changesets... duh!
  • Property svn:eol-style set to native
File size: 6.9 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.data.osm.Changeset;
9import org.openstreetmap.josm.data.osm.DataSet;
10import org.openstreetmap.josm.data.osm.DataSource;
11import org.openstreetmap.josm.data.osm.Node;
12import org.openstreetmap.josm.data.osm.OsmPrimitive;
13import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
14import org.openstreetmap.josm.data.osm.Relation;
15import org.openstreetmap.josm.data.osm.RelationMember;
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    public final String DEFAULT_API_VERSION = "0.6";
28
29    /**
30     * The counter for newly created objects. Starts at -1 and goes down.
31     */
32    private long newIdCounter = -1;
33
34    /**
35     * All newly created ids and their primitive that uses it. This is a back reference
36     * map to allow references to use the correnct primitives.
37     */
38    public HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
39
40    private boolean osmConform;
41    private boolean withBody = true;
42    private String version;
43    private Changeset changeset;
44
45    public OsmWriter(PrintWriter out, boolean osmConform, String version) {
46        super(out);
47        this.osmConform = osmConform;
48        this.version = (version == null ? DEFAULT_API_VERSION : version);
49    }
50
51    public void setWithBody(boolean wb) {
52        this.withBody = wb;
53    }
54    public void setChangeset(Changeset cs) {
55        this.changeset = cs;
56    }
57    public void setVersion(String v) {
58        this.version = v;
59    }
60
61    public void header() {
62        out.println("<?xml version='1.0' encoding='UTF-8'?>");
63        out.print("<osm version='");
64        out.print(version);
65        out.println("' generator='JOSM'>");
66    }
67    public void footer() {
68        out.println("</osm>");
69    }
70
71    public void writeContent(DataSet ds) {
72        for (Node n : ds.nodes)
73            if (shouldWrite(n)) {
74                visit(n);
75            }
76        for (Way w : ds.ways)
77            if (shouldWrite(w)) {
78                visit(w);
79            }
80        for (Relation e : ds.relations)
81            if (shouldWrite(e)) {
82                visit(e);
83            }
84    }
85
86    private boolean shouldWrite(OsmPrimitive osm) {
87        return osm.id != 0 || !osm.deleted;
88    }
89
90    public void writeDataSources(DataSet ds) {
91        for (DataSource s : ds.dataSources) {
92            out.println("  <bounds minlat='"
93                    + s.bounds.min.lat()+"' minlon='"
94                    + s.bounds.min.lon()+"' maxlat='"
95                    + s.bounds.max.lat()+"' maxlon='"
96                    + s.bounds.max.lon()
97                    +"' origin='"+XmlWriter.encode(s.origin)+"' />");
98        }
99    }
100
101    public void visit(Node n) {
102        if (n.incomplete) return;
103        addCommon(n, "node");
104        out.print(" lat='"+n.getCoor().lat()+"' lon='"+n.getCoor().lon()+"'");
105        if (!withBody) {
106            out.println("/>");
107        } else {
108            addTags(n, "node", true);
109        }
110    }
111
112    public void visit(Way w) {
113        if (w.incomplete) return;
114        addCommon(w, "way");
115        if (!withBody) {
116            out.println("/>");
117        } else {
118            out.println(">");
119            for (Node n : w.nodes) {
120                out.println("    <nd ref='"+getUsedId(n)+"' />");
121            }
122            addTags(w, "way", false);
123        }
124    }
125
126    public void visit(Relation e) {
127        if (e.incomplete) return;
128        addCommon(e, "relation");
129        if (!withBody) {
130            out.println("/>");
131        } else {
132            out.println(">");
133            for (RelationMember em : e.members) {
134                out.print("    <member type='");
135                out.print(OsmPrimitiveType.from(em.member).getAPIName());
136                out.println("' ref='"+getUsedId(em.member)+"' role='" +
137                        XmlWriter.encode(em.role == null ? "" : em.role) + "' />");
138            }
139            addTags(e, "relation", false);
140        }
141    }
142
143    public void visit(Changeset cs) {
144        addCommon(cs, "changeset");
145        out.println(">\n");
146        addTags(cs, "changeset", false);
147    }
148
149    public final void footer(PrintWriter out) {
150        out.println("</osm>");
151    }
152
153    /**
154     * Return the id for the given osm primitive (may access the usedId map)
155     */
156    private long getUsedId(OsmPrimitive osm) {
157        if (osm.id != 0)
158            return osm.id;
159        if (usedNewIds.containsKey(osm))
160            return usedNewIds.get(osm);
161        usedNewIds.put(osm, newIdCounter);
162        return osmConform ? 0 : newIdCounter--;
163    }
164
165    private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
166        if (osm.keys != null) {
167            if (tagOpen) {
168                out.println(">");
169            }
170            for (Entry<String, String> e : osm.keys.entrySet()) {
171                if ((osm instanceof Changeset) || !("created_by".equals(e.getKey())))
172                    out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
173                            "' v='"+XmlWriter.encode(e.getValue())+ "' />");
174            }
175            out.println("  </" + tagname + ">");
176        } else if (tagOpen) {
177            out.println(" />");
178        } else {
179            out.println("  </" + tagname + ">");
180        }
181    }
182
183    /**
184     * Add the common part as the form of the tag as well as the XML attributes
185     * id, action, user, and visible.
186     */
187    private void addCommon(OsmPrimitive osm, String tagname) {
188        long id = getUsedId(osm);
189        out.print("  <"+tagname);
190        if (id != 0) {
191            out.print(" id='"+getUsedId(osm)+"'");
192        }
193        if (!osmConform) {
194            String action = null;
195            if (osm.deleted) {
196                action = "delete";
197            } else if (osm.modified) {
198                action = "modify";
199            }
200            if (action != null) {
201                out.print(" action='"+action+"'");
202            }
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        }
215        if (this.changeset != null && this.changeset.id != 0) {
216            out.print(" changeset='"+this.changeset.id+"'" );
217        }
218    }
219
220    public void close() {
221        out.close();
222    }
223
224    public void flush() {
225        out.flush();
226    }
227}
Note: See TracBrowser for help on using the repository browser.