// License: GPL. Copyright 2007 by Immanuel Scholz and others
package org.openstreetmap.josm.io;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import org.openstreetmap.josm.data.coor.CoordinateFormat;
import org.openstreetmap.josm.data.osm.Changeset;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.DataSource;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.data.osm.Tagged;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.data.osm.visitor.Visitor;
import org.openstreetmap.josm.tools.DateUtils;
/**
* Save the dataset into a stream as osm intern xml format. This is not using any
* xml library for storing.
* @author imi
*/
public class OsmWriter extends XmlWriter implements Visitor {
public static final String DEFAULT_API_VERSION = "0.6";
private boolean osmConform;
private boolean withBody = true;
private String version;
private Changeset changeset;
public OsmWriter(PrintWriter out, boolean osmConform, String version) {
super(out);
this.osmConform = osmConform;
this.version = (version == null ? DEFAULT_API_VERSION : version);
}
public void setWithBody(boolean wb) {
this.withBody = wb;
}
public void setChangeset(Changeset cs) {
this.changeset = cs;
}
public void setVersion(String v) {
this.version = v;
}
public void header() {
out.println("");
out.print("");
}
public void footer() {
out.println("");
}
private static final Comparator byIdComparator = new Comparator() {
public int compare(OsmPrimitive o1, OsmPrimitive o2) {
return (o1.getUniqueId() sortById(Collection extends OsmPrimitive> primitives) {
List result = new ArrayList(primitives.size());
result.addAll(primitives);
Collections.sort(result, byIdComparator);
return result;
}
public void writeContent(DataSet ds) {
for (OsmPrimitive n : sortById(ds.getNodes())) {
if (shouldWrite(n)) {
visit((Node)n);
}
}
for (OsmPrimitive w : sortById(ds.getWays())) {
if (shouldWrite(w)) {
visit((Way)w);
}
}
for (OsmPrimitive e: sortById(ds.getRelations())) {
if (shouldWrite(e)) {
visit((Relation)e);
}
}
}
private boolean shouldWrite(OsmPrimitive osm) {
return !osm.isNewOrUndeleted() || !osm.isDeleted();
}
public void writeDataSources(DataSet ds) {
for (DataSource s : ds.dataSources) {
out.println(" ");
}
}
public void visit(Node n) {
if (n.isIncomplete()) return;
addCommon(n, "node");
out.print(" lat='"+n.getCoor().lat()+"' lon='"+n.getCoor().lon()+"'");
if (!withBody) {
out.println("/>");
} else {
addTags(n, "node", true);
}
}
public void visit(Way w) {
if (w.isIncomplete()) return;
addCommon(w, "way");
if (!withBody) {
out.println("/>");
} else {
out.println(">");
for (Node n : w.getNodes()) {
out.println(" ");
}
addTags(w, "way", false);
}
}
public void visit(Relation e) {
if (e.isIncomplete()) return;
addCommon(e, "relation");
if (!withBody) {
out.println("/>");
} else {
out.println(">");
for (RelationMember em : e.getMembers()) {
out.print(" ");
}
addTags(e, "relation", false);
}
}
public void visit(Changeset cs) {
out.print(" ");
addTags(cs, "changeset", false); // also writes closing
}
private static final Comparator> byKeyComparator = new Comparator>() {
public int compare(Entry o1, Entry o2) {
return o1.getKey().compareTo(o2.getKey());
}
};
private void addTags(Tagged osm, String tagname, boolean tagOpen) {
if (osm.hasKeys()) {
if (tagOpen) {
out.println(">");
}
List> entries = new ArrayList>(osm.getKeys().entrySet());
Collections.sort(entries, byKeyComparator);
for (Entry e : entries) {
if ((osm instanceof Changeset) || !("created_by".equals(e.getKey()))) {
out.println(" ");
}
}
out.println(" " + tagname + ">");
} else if (tagOpen) {
out.println(" />");
} else {
out.println(" " + tagname + ">");
}
}
/**
* Add the common part as the form of the tag as well as the XML attributes
* id, action, user, and visible.
*/
private void addCommon(OsmPrimitive osm, String tagname) {
out.print(" <"+tagname);
if (osm.getUniqueId() != 0) {
out.print(" id='"+ osm.getUniqueId()+"'");
} else
throw new IllegalStateException(tr("Unexpected id 0 for osm primitive found"));
if (!osmConform) {
String action = null;
if (osm.isDeleted()) {
action = "delete";
} else if (osm.isModified()) {
action = "modify";
}
if (action != null) {
out.print(" action='"+action+"'");
}
}
if (!osm.isTimestampEmpty()) {
out.print(" timestamp='"+DateUtils.fromDate(osm.getTimestamp())+"'");
}
// user and visible added with 0.4 API
if (osm.getUser() != null) {
if(osm.getUser().isLocalUser()) {
out.print(" user='"+XmlWriter.encode(osm.getUser().getName())+"'");
} else if (osm.getUser().isOsmUser()) {
// uid added with 0.6
out.print(" uid='"+ osm.getUser().getId()+"'");
out.print(" user='"+XmlWriter.encode(osm.getUser().getName())+"'");
}
}
out.print(" visible='"+osm.isVisible()+"'");
if (osm.getVersion() != 0) {
out.print(" version='"+osm.getVersion()+"'");
}
if (this.changeset != null && this.changeset.getId() != 0) {
out.print(" changeset='"+this.changeset.getId()+"'" );
} else if (osm.getChangesetId() > 0 && !osm.isNew()) {
out.print(" changeset='"+osm.getChangesetId()+"'" );
}
}
public void close() {
out.close();
}
public void flush() {
out.flush();
}
}