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

Revision 5025, 9.8 KB checked in by Don-vip, 3 months ago (diff)

see #4043 - Have an 'upload prohibited' flag in .osm files

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