source: josm/trunk/src/org/openstreetmap/josm/io/OsmJsonReader.java@ 14086

Last change on this file since 14086 was 14086, checked in by Don-vip, 6 years ago

fix #16546 - Support Overpass API JSON format

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.InputStream;
7import java.util.Collection;
8import java.util.Map.Entry;
9
10import javax.json.Json;
11import javax.json.JsonArray;
12import javax.json.JsonNumber;
13import javax.json.JsonObject;
14import javax.json.JsonString;
15import javax.json.JsonValue;
16import javax.json.stream.JsonParser;
17import javax.json.stream.JsonParser.Event;
18
19import org.openstreetmap.josm.data.osm.DataSet;
20import org.openstreetmap.josm.data.osm.PrimitiveData;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.RelationMemberData;
23import org.openstreetmap.josm.data.osm.Tagged;
24import org.openstreetmap.josm.data.osm.Way;
25import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
26import org.openstreetmap.josm.gui.progress.ProgressMonitor;
27import org.openstreetmap.josm.tools.Logging;
28import org.openstreetmap.josm.tools.UncheckedParseException;
29
30/**
31 * Parser for the Osm API (JSON output). Read from an input stream and construct a dataset out of it.
32 *
33 * For each json element, there is a dedicated method.
34 * @since 14086
35 */
36public class OsmJsonReader extends AbstractReader {
37
38 protected JsonParser parser;
39
40 /**
41 * constructor (for private and subclasses use only)
42 *
43 * @see #parseDataSet(InputStream, ProgressMonitor)
44 */
45 protected OsmJsonReader() {
46 // Restricts visibility
47 }
48
49 protected void setParser(JsonParser parser) {
50 this.parser = parser;
51 }
52
53 protected void parse() throws IllegalDataException {
54 while (parser.hasNext()) {
55 Event event = parser.next();
56 if (event == Event.START_OBJECT) {
57 parseRoot(parser.getObject());
58 }
59 }
60 parser.close();
61 }
62
63 private void parseRoot(JsonObject object) throws IllegalDataException {
64 parseVersion(object.get("version").toString());
65 parseDownloadPolicy("download", object.getString("download", null));
66 parseUploadPolicy("upload", object.getString("upload", null));
67 parseLocked(object.getString("locked", null));
68 parseElements(object.getJsonArray("elements"));
69 }
70
71 private void parseElements(JsonArray jsonArray) throws IllegalDataException {
72 for (JsonValue value : jsonArray) {
73 if (value instanceof JsonObject) {
74 JsonObject item = (JsonObject) value;
75 switch (item.getString("type")) {
76 case "node":
77 parseNode(item);
78 break;
79 case "way":
80 parseWay(item);
81 break;
82 case "relation":
83 parseRelation(item);
84 break;
85 default:
86 parseUnknown(item);
87 }
88 } else {
89 throw new IllegalDataException("Unexpected JSON item: " + value);
90 }
91 }
92 }
93
94 /**
95 * Read out the common attributes and put them into current OsmPrimitive.
96 * @param item current JSON object
97 * @param current primitive to update
98 * @throws IllegalDataException if there is an error processing the underlying JSON source
99 */
100 private void readCommon(JsonObject item, PrimitiveData current) throws IllegalDataException {
101 try {
102 parseId(current, item.getJsonNumber("id").longValue());
103 parseTimestamp(current, item.getString("timestamp", null));
104 JsonNumber uid = item.getJsonNumber("uid");
105 if (uid != null) {
106 parseUser(current, item.getString("user", null), uid.longValue());
107 }
108 parseVisible(current, item.getString("visible", null));
109 JsonNumber version = item.getJsonNumber("version");
110 if (version != null) {
111 parseVersion(current, version.intValue());
112 }
113 parseAction(current, item.getString("action", null));
114 JsonNumber changeset = item.getJsonNumber("changeset");
115 if (changeset != null) {
116 parseChangeset(current, changeset.intValue());
117 }
118 } catch (UncheckedParseException e) {
119 throw new IllegalDataException(e);
120 }
121 }
122
123 private void readTags(JsonObject item, Tagged t) {
124 JsonObject tags = item.getJsonObject("tags");
125 if (tags != null) {
126 for (Entry<String, JsonValue> entry : tags.entrySet()) {
127 t.put(entry.getKey(), ((JsonString) entry.getValue()).getString());
128 }
129 }
130 }
131
132 private void parseNode(JsonObject item) throws IllegalDataException {
133 parseNode(item.getJsonNumber("lat").doubleValue(),
134 item.getJsonNumber("lon").doubleValue(), nd -> readCommon(item, nd), n -> readTags(item, n));
135 }
136
137 private void parseWay(JsonObject item) throws IllegalDataException {
138 parseWay(wd -> readCommon(item, wd), (w, nodeIds) -> readWayNodesAndTags(item, w, nodeIds));
139 }
140
141 private void readWayNodesAndTags(JsonObject item, Way w, Collection<Long> nodeIds) {
142 for (JsonValue v : item.getJsonArray("nodes")) {
143 nodeIds.add(((JsonNumber) v).longValue());
144 }
145 readTags(item, w);
146 }
147
148 private void parseRelation(JsonObject item) throws IllegalDataException {
149 parseRelation(rd -> readCommon(item, rd), (r, members) -> readRelationMembersAndTags(item, r, members));
150 }
151
152 private void readRelationMembersAndTags(JsonObject item, Relation r, Collection<RelationMemberData> members)
153 throws IllegalDataException {
154 for (JsonValue v : item.getJsonArray("members")) {
155 JsonObject o = v.asJsonObject();
156 members.add(parseRelationMember(r, ((JsonNumber) o.get("ref")).longValue(), o.getString("type"), o.getString("role")));
157 }
158 readTags(item, r);
159 }
160
161 protected void parseUnknown(JsonObject element, boolean printWarning) {
162 if (printWarning) {
163 Logging.info(tr("Undefined element ''{0}'' found in input stream. Skipping.", element));
164 }
165 }
166
167 private void parseUnknown(JsonObject element) {
168 parseUnknown(element, true);
169 }
170
171 @Override
172 protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
173 return doParseDataSet(source, progressMonitor, ir -> {
174 setParser(Json.createParser(ir));
175 parse();
176 });
177 }
178
179 /**
180 * Parse the given input source and return the dataset.
181 *
182 * @param source the source input stream. Must not be null.
183 * @param progressMonitor the progress monitor. If null, {@link NullProgressMonitor#INSTANCE} is assumed
184 *
185 * @return the dataset with the parsed data
186 * @throws IllegalDataException if an error was found while parsing the data from the source
187 * @throws IllegalArgumentException if source is null
188 */
189 public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
190 return new OsmJsonReader().doParseDataSet(source, progressMonitor);
191 }
192}
Note: See TracBrowser for help on using the repository browser.