source: josm/trunk/src/org/openstreetmap/josm/io/NameFinder.java@ 11003

Last change on this file since 11003 was 11003, checked in by simon04, 8 years ago

fix #11975 - Evaluate extended Overpass queries bbox, geocodeArea

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.IOException;
7import java.io.Reader;
8import java.net.URL;
9import java.util.LinkedList;
10import java.util.List;
11
12import javax.xml.parsers.ParserConfigurationException;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.Bounds;
16import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
17import org.openstreetmap.josm.data.osm.PrimitiveId;
18import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
19import org.openstreetmap.josm.tools.HttpClient;
20import org.openstreetmap.josm.tools.OsmUrlToBounds;
21import org.openstreetmap.josm.tools.UncheckedParseException;
22import org.openstreetmap.josm.tools.Utils;
23import org.xml.sax.Attributes;
24import org.xml.sax.InputSource;
25import org.xml.sax.SAXException;
26import org.xml.sax.helpers.DefaultHandler;
27
28/**
29 * Search for names and related items.
30 * @since 11002
31 */
32public class NameFinder {
33
34 public static final String NOMINATIM_URL = "https://nominatim.openstreetmap.org/search?format=xml&q=";
35
36 private NameFinder() {
37 }
38
39 public static List<SearchResult> queryNominatim(final String searchExpression) throws IOException {
40 return query(new URL(NOMINATIM_URL + Utils.encodeUrl(searchExpression)));
41 }
42
43 public static List<SearchResult> query(final URL url) throws IOException {
44 final HttpClient connection = HttpClient.create(url);
45 connection.connect();
46 try (Reader reader = connection.getResponse().getContentReader()) {
47 return parseSearchResults(reader);
48 } catch (ParserConfigurationException | SAXException ex) {
49 throw new UncheckedParseException(ex);
50 }
51 }
52
53 public static List<SearchResult> parseSearchResults(Reader reader) throws IOException, ParserConfigurationException, SAXException {
54 InputSource inputSource = new InputSource(reader);
55 NameFinderResultParser parser = new NameFinderResultParser();
56 Utils.parseSafeSAX(inputSource, parser);
57 return parser.getResult();
58 }
59
60 /**
61 * Data storage for search results.
62 */
63 public static class SearchResult {
64 public String name;
65 public String info;
66 public String nearestPlace;
67 public String description;
68 public double lat;
69 public double lon;
70 public int zoom;
71 public Bounds bounds;
72 public PrimitiveId osmId;
73
74 public Bounds getDownloadArea() {
75 return bounds != null ? bounds : OsmUrlToBounds.positionToBounds(lat, lon, zoom);
76 }
77 }
78
79 /**
80 * A very primitive parser for the name finder's output.
81 * Structure of xml described here: http://wiki.openstreetmap.org/index.php/Name_finder
82 */
83 private static class NameFinderResultParser extends DefaultHandler {
84 private SearchResult currentResult;
85 private StringBuilder description;
86 private int depth;
87 private final List<SearchResult> data = new LinkedList<>();
88
89 /**
90 * Detect starting elements.
91 */
92 @Override
93 public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
94 throws SAXException {
95 depth++;
96 try {
97 if ("searchresults".equals(qName)) {
98 // do nothing
99 } else if ("named".equals(qName) && (depth == 2)) {
100 currentResult = new SearchResult();
101 currentResult.name = atts.getValue("name");
102 currentResult.info = atts.getValue("info");
103 if (currentResult.info != null) {
104 currentResult.info = tr(currentResult.info);
105 }
106 currentResult.lat = Double.parseDouble(atts.getValue("lat"));
107 currentResult.lon = Double.parseDouble(atts.getValue("lon"));
108 currentResult.zoom = Integer.parseInt(atts.getValue("zoom"));
109 data.add(currentResult);
110 } else if ("description".equals(qName) && (depth == 3)) {
111 description = new StringBuilder();
112 } else if ("named".equals(qName) && (depth == 4)) {
113 // this is a "named" place in the nearest places list.
114 String info = atts.getValue("info");
115 if ("city".equals(info) || "town".equals(info) || "village".equals(info)) {
116 currentResult.nearestPlace = atts.getValue("name");
117 }
118 } else if ("place".equals(qName) && atts.getValue("lat") != null) {
119 currentResult = new SearchResult();
120 currentResult.name = atts.getValue("display_name");
121 currentResult.description = currentResult.name;
122 currentResult.info = atts.getValue("class");
123 if (currentResult.info != null) {
124 currentResult.info = tr(currentResult.info);
125 }
126 currentResult.nearestPlace = tr(atts.getValue("type"));
127 currentResult.lat = Double.parseDouble(atts.getValue("lat"));
128 currentResult.lon = Double.parseDouble(atts.getValue("lon"));
129 String[] bbox = atts.getValue("boundingbox").split(",");
130 currentResult.bounds = new Bounds(
131 Double.parseDouble(bbox[0]), Double.parseDouble(bbox[2]),
132 Double.parseDouble(bbox[1]), Double.parseDouble(bbox[3]));
133 final String osmId = atts.getValue("osm_id");
134 final String osmType = atts.getValue("osm_type");
135 if (osmId != null && osmType != null) {
136 currentResult.osmId = new SimplePrimitiveId(Long.parseLong(osmId), OsmPrimitiveType.from(osmType));
137 }
138 data.add(currentResult);
139 }
140 } catch (NumberFormatException x) {
141 Main.error(x); // SAXException does not chain correctly
142 throw new SAXException(x.getMessage(), x);
143 } catch (NullPointerException x) {
144 Main.error(x); // SAXException does not chain correctly
145 throw new SAXException(tr("Null pointer exception, possibly some missing tags."), x);
146 }
147 }
148
149 /**
150 * Detect ending elements.
151 */
152 @Override
153 public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
154 if ("description".equals(qName) && description != null) {
155 currentResult.description = description.toString();
156 description = null;
157 }
158 depth--;
159 }
160
161 /**
162 * Read characters for description.
163 */
164 @Override
165 public void characters(char[] data, int start, int length) throws SAXException {
166 if (description != null) {
167 description.append(data, start, length);
168 }
169 }
170
171 public List<SearchResult> getResult() {
172 return data;
173 }
174 }
175}
Note: See TracBrowser for help on using the repository browser.