1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.io;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.io.InputStream;
|
---|
7 | import java.util.Collection;
|
---|
8 | import java.util.Map.Entry;
|
---|
9 |
|
---|
10 | import javax.json.Json;
|
---|
11 | import javax.json.JsonArray;
|
---|
12 | import javax.json.JsonNumber;
|
---|
13 | import javax.json.JsonObject;
|
---|
14 | import javax.json.JsonString;
|
---|
15 | import javax.json.JsonValue;
|
---|
16 | import javax.json.stream.JsonParser;
|
---|
17 | import javax.json.stream.JsonParser.Event;
|
---|
18 |
|
---|
19 | import org.openstreetmap.josm.data.osm.DataSet;
|
---|
20 | import org.openstreetmap.josm.data.osm.PrimitiveData;
|
---|
21 | import org.openstreetmap.josm.data.osm.Relation;
|
---|
22 | import org.openstreetmap.josm.data.osm.RelationMemberData;
|
---|
23 | import org.openstreetmap.josm.data.osm.Tagged;
|
---|
24 | import org.openstreetmap.josm.data.osm.Way;
|
---|
25 | import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
---|
26 | import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
---|
27 | import org.openstreetmap.josm.tools.Logging;
|
---|
28 | import 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 | */
|
---|
36 | public 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 | parseRemark(object.getString("remark", null));
|
---|
70 | }
|
---|
71 |
|
---|
72 | private void parseRemark(String remark) {
|
---|
73 | ds.setRemark(remark);
|
---|
74 | }
|
---|
75 |
|
---|
76 | private void parseElements(JsonArray jsonArray) throws IllegalDataException {
|
---|
77 | for (JsonValue value : jsonArray) {
|
---|
78 | if (value instanceof JsonObject) {
|
---|
79 | JsonObject item = (JsonObject) value;
|
---|
80 | switch (item.getString("type")) {
|
---|
81 | case "node":
|
---|
82 | parseNode(item);
|
---|
83 | break;
|
---|
84 | case "way":
|
---|
85 | parseWay(item);
|
---|
86 | break;
|
---|
87 | case "relation":
|
---|
88 | parseRelation(item);
|
---|
89 | break;
|
---|
90 | default:
|
---|
91 | parseUnknown(item);
|
---|
92 | }
|
---|
93 | } else {
|
---|
94 | throw new IllegalDataException("Unexpected JSON item: " + value);
|
---|
95 | }
|
---|
96 | }
|
---|
97 | }
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * Read out the common attributes and put them into current OsmPrimitive.
|
---|
101 | * @param item current JSON object
|
---|
102 | * @param current primitive to update
|
---|
103 | * @throws IllegalDataException if there is an error processing the underlying JSON source
|
---|
104 | */
|
---|
105 | private void readCommon(JsonObject item, PrimitiveData current) throws IllegalDataException {
|
---|
106 | try {
|
---|
107 | parseId(current, item.getJsonNumber("id").longValue());
|
---|
108 | parseTimestamp(current, item.getString("timestamp", null));
|
---|
109 | JsonNumber uid = item.getJsonNumber("uid");
|
---|
110 | if (uid != null) {
|
---|
111 | parseUser(current, item.getString("user", null), uid.longValue());
|
---|
112 | }
|
---|
113 | parseVisible(current, item.getString("visible", null));
|
---|
114 | JsonNumber version = item.getJsonNumber("version");
|
---|
115 | if (version != null) {
|
---|
116 | parseVersion(current, version.intValue());
|
---|
117 | }
|
---|
118 | parseAction(current, item.getString("action", null));
|
---|
119 | JsonNumber changeset = item.getJsonNumber("changeset");
|
---|
120 | if (changeset != null) {
|
---|
121 | parseChangeset(current, changeset.intValue());
|
---|
122 | }
|
---|
123 | } catch (UncheckedParseException e) {
|
---|
124 | throw new IllegalDataException(e);
|
---|
125 | }
|
---|
126 | }
|
---|
127 |
|
---|
128 | private static void readTags(JsonObject item, Tagged t) {
|
---|
129 | JsonObject tags = item.getJsonObject("tags");
|
---|
130 | if (tags != null) {
|
---|
131 | for (Entry<String, JsonValue> entry : tags.entrySet()) {
|
---|
132 | t.put(entry.getKey(), ((JsonString) entry.getValue()).getString());
|
---|
133 | }
|
---|
134 | }
|
---|
135 | }
|
---|
136 |
|
---|
137 | private void parseNode(JsonObject item) throws IllegalDataException {
|
---|
138 | parseNode(item.getJsonNumber("lat").doubleValue(),
|
---|
139 | item.getJsonNumber("lon").doubleValue(), nd -> readCommon(item, nd), n -> readTags(item, n));
|
---|
140 | }
|
---|
141 |
|
---|
142 | private void parseWay(JsonObject item) throws IllegalDataException {
|
---|
143 | parseWay(wd -> readCommon(item, wd), (w, nodeIds) -> readWayNodesAndTags(item, w, nodeIds));
|
---|
144 | }
|
---|
145 |
|
---|
146 | private static void readWayNodesAndTags(JsonObject item, Way w, Collection<Long> nodeIds) {
|
---|
147 | for (JsonValue v : item.getJsonArray("nodes")) {
|
---|
148 | nodeIds.add(((JsonNumber) v).longValue());
|
---|
149 | }
|
---|
150 | readTags(item, w);
|
---|
151 | }
|
---|
152 |
|
---|
153 | private void parseRelation(JsonObject item) throws IllegalDataException {
|
---|
154 | parseRelation(rd -> readCommon(item, rd), (r, members) -> readRelationMembersAndTags(item, r, members));
|
---|
155 | }
|
---|
156 |
|
---|
157 | private void readRelationMembersAndTags(JsonObject item, Relation r, Collection<RelationMemberData> members)
|
---|
158 | throws IllegalDataException {
|
---|
159 | for (JsonValue v : item.getJsonArray("members")) {
|
---|
160 | JsonObject o = v.asJsonObject();
|
---|
161 | members.add(parseRelationMember(r, ((JsonNumber) o.get("ref")).longValue(), o.getString("type"), o.getString("role")));
|
---|
162 | }
|
---|
163 | readTags(item, r);
|
---|
164 | }
|
---|
165 |
|
---|
166 | protected void parseUnknown(JsonObject element, boolean printWarning) {
|
---|
167 | if (printWarning) {
|
---|
168 | Logging.info(tr("Undefined element ''{0}'' found in input stream. Skipping.", element));
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | private void parseUnknown(JsonObject element) {
|
---|
173 | parseUnknown(element, true);
|
---|
174 | }
|
---|
175 |
|
---|
176 | @Override
|
---|
177 | protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
---|
178 | return doParseDataSet(source, progressMonitor, ir -> {
|
---|
179 | setParser(Json.createParser(ir));
|
---|
180 | parse();
|
---|
181 | });
|
---|
182 | }
|
---|
183 |
|
---|
184 | /**
|
---|
185 | * Parse the given input source and return the dataset.
|
---|
186 | *
|
---|
187 | * @param source the source input stream. Must not be null.
|
---|
188 | * @param progressMonitor the progress monitor. If null, {@link NullProgressMonitor#INSTANCE} is assumed
|
---|
189 | *
|
---|
190 | * @return the dataset with the parsed data
|
---|
191 | * @throws IllegalDataException if an error was found while parsing the data from the source
|
---|
192 | * @throws IllegalArgumentException if source is null
|
---|
193 | */
|
---|
194 | public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
---|
195 | return new OsmJsonReader().doParseDataSet(source, progressMonitor);
|
---|
196 | }
|
---|
197 | }
|
---|