X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/35b52c46562c3dd3427da7bca898d18edfd60047..41383c05cd65a36c518f9adce55cfec2a9be00d0:/nominatim/api/v1/format_json.py diff --git a/nominatim/api/v1/format_json.py b/nominatim/api/v1/format_json.py index 898e6213..1c17a032 100644 --- a/nominatim/api/v1/format_json.py +++ b/nominatim/api/v1/format_json.py @@ -7,16 +7,17 @@ """ Helper functions for output of results in json formats. """ -from typing import Mapping, Any, Optional, Tuple +from typing import Mapping, Any, Optional, Tuple, Union import nominatim.api as napi -from nominatim.api.v1.constants import OSM_ATTRIBUTION, OSM_TYPE_NAME, bbox_from_result -from nominatim.api.v1.classtypes import ICONS, get_label_tag +import nominatim.api.v1.classtypes as cl from nominatim.utils.json_writer import JsonWriter +#pylint: disable=too-many-branches + def _write_osm_id(out: JsonWriter, osm_object: Optional[Tuple[str, int]]) -> None: if osm_object is not None: - out.keyval_not_none('osm_type', OSM_TYPE_NAME.get(osm_object[0], None))\ + out.keyval_not_none('osm_type', cl.OSM_TYPE_NAME.get(osm_object[0], None))\ .keyval('osm_id', osm_object[1]) @@ -24,11 +25,14 @@ def _write_typed_address(out: JsonWriter, address: Optional[napi.AddressLines], country_code: Optional[str]) -> None: parts = {} for line in (address or []): - if line.isaddress and line.local_name: - label = get_label_tag(line.category, line.extratags, - line.rank_address, country_code) - if label not in parts: - parts[label] = line.local_name + if line.isaddress: + if line.local_name: + label = cl.get_label_tag(line.category, line.extratags, + line.rank_address, country_code) + if label not in parts: + parts[label] = line.local_name + if line.names and 'ISO3166-2' in line.names and line.admin_level: + parts[f"ISO3166-2-lvl{line.admin_level}"] = line.names['ISO3166-2'] for k, v in parts.items(): out.keyval(k, v) @@ -50,7 +54,10 @@ def _write_geocodejson_address(out: JsonWriter, out.keyval('housenumber', line.local_name) elif (obj_place_id is None or obj_place_id != line.place_id) \ and line.rank_address >= 4 and line.rank_address < 28: - extra[GEOCODEJSON_RANKS[line.rank_address]] = line.local_name + rank_name = GEOCODEJSON_RANKS[line.rank_address] + if rank_name not in extra: + extra[rank_name] = line.local_name + for k, v in extra.items(): out.keyval(k, v) @@ -59,13 +66,11 @@ def _write_geocodejson_address(out: JsonWriter, out.keyval('country_code', country_code) -def format_base_json(results: napi.ReverseResults, #pylint: disable=too-many-branches +def format_base_json(results: Union[napi.ReverseResults, napi.SearchResults], options: Mapping[str, Any], simple: bool, class_label: str) -> str: """ Return the result list as a simple json string in custom Nominatim format. """ - locales = options.get('locales', napi.Locales()) - out = JsonWriter() if simple: @@ -75,29 +80,27 @@ def format_base_json(results: napi.ReverseResults, #pylint: disable=too-many-bra out.start_array() for result in results: - label_parts = result.address_rows.localize(locales) if result.address_rows else [] - out.start_object()\ .keyval_not_none('place_id', result.place_id)\ - .keyval('licence', OSM_ATTRIBUTION)\ + .keyval('licence', cl.OSM_ATTRIBUTION)\ _write_osm_id(out, result.osm_object) - out.keyval('lat', result.centroid.lat)\ - .keyval('lon', result.centroid.lon)\ + out.keyval('lat', f"{result.centroid.lat}")\ + .keyval('lon', f"{result.centroid.lon}")\ .keyval(class_label, result.category[0])\ .keyval('type', result.category[1])\ .keyval('place_rank', result.rank_search)\ .keyval('importance', result.calculated_importance())\ - .keyval('addresstype', get_label_tag(result.category, result.extratags, - result.rank_address, - result.country_code))\ - .keyval('name', locales.display_name(result.names))\ - .keyval('display_name', ', '.join(label_parts)) + .keyval('addresstype', cl.get_label_tag(result.category, result.extratags, + result.rank_address, + result.country_code))\ + .keyval('name', result.locale_name or '')\ + .keyval('display_name', result.display_name or '') if options.get('icon_base_url', None): - icon = ICONS.get(result.category) + icon = cl.ICONS.get(result.category) if icon: out.keyval('icon', f"{options['icon_base_url']}/{icon}.p.20.png") @@ -112,12 +115,12 @@ def format_base_json(results: napi.ReverseResults, #pylint: disable=too-many-bra if options.get('namedetails', False): out.keyval('namedetails', result.names) - bbox = bbox_from_result(result) + bbox = cl.bbox_from_result(result) out.key('boundingbox').start_array()\ - .value(bbox.minlat).next()\ - .value(bbox.maxlat).next()\ - .value(bbox.minlon).next()\ - .value(bbox.maxlon).next()\ + .value(f"{bbox.minlat:0.7f}").next()\ + .value(f"{bbox.maxlat:0.7f}").next()\ + .value(f"{bbox.minlon:0.7f}").next()\ + .value(f"{bbox.maxlon:0.7f}").next()\ .end_array().next() if result.geometry: @@ -139,7 +142,7 @@ def format_base_json(results: napi.ReverseResults, #pylint: disable=too-many-bra return out() -def format_base_geojson(results: napi.ReverseResults, +def format_base_geojson(results: Union[napi.ReverseResults, napi.SearchResults], options: Mapping[str, Any], simple: bool) -> str: """ Return the result list as a geojson string. @@ -147,21 +150,14 @@ def format_base_geojson(results: napi.ReverseResults, if not results and simple: return '{"error":"Unable to geocode"}' - locales = options.get('locales', napi.Locales()) - out = JsonWriter() out.start_object()\ .keyval('type', 'FeatureCollection')\ - .keyval('licence', OSM_ATTRIBUTION)\ + .keyval('licence', cl.OSM_ATTRIBUTION)\ .key('features').start_array() for result in results: - if result.address_rows: - label_parts = result.address_rows.localize(locales) - else: - label_parts = [] - out.start_object()\ .keyval('type', 'Feature')\ .key('properties').start_object() @@ -174,11 +170,11 @@ def format_base_geojson(results: napi.ReverseResults, .keyval('category', result.category[0])\ .keyval('type', result.category[1])\ .keyval('importance', result.calculated_importance())\ - .keyval('addresstype', get_label_tag(result.category, result.extratags, - result.rank_address, - result.country_code))\ - .keyval('name', locales.display_name(result.names))\ - .keyval('display_name', ', '.join(label_parts)) + .keyval('addresstype', cl.get_label_tag(result.category, result.extratags, + result.rank_address, + result.country_code))\ + .keyval('name', result.locale_name or '')\ + .keyval('display_name', result.display_name or '') if options.get('addressdetails', False): out.key('address').start_object() @@ -193,8 +189,10 @@ def format_base_geojson(results: napi.ReverseResults, out.end_object().next() # properties - bbox = bbox_from_result(result) - out.keyval('bbox', bbox.coords) + out.key('bbox').start_array() + for coord in cl.bbox_from_result(result).coords: + out.float(coord, 7).next() + out.end_array().next() out.key('geometry').raw(result.geometry.get('geojson') or result.centroid.to_geojson()).next() @@ -206,33 +204,26 @@ def format_base_geojson(results: napi.ReverseResults, return out() -def format_base_geocodejson(results: napi.ReverseResults, +def format_base_geocodejson(results: Union[napi.ReverseResults, napi.SearchResults], options: Mapping[str, Any], simple: bool) -> str: """ Return the result list as a geocodejson string. """ if not results and simple: return '{"error":"Unable to geocode"}' - locales = options.get('locales', napi.Locales()) - out = JsonWriter() out.start_object()\ .keyval('type', 'FeatureCollection')\ .key('geocoding').start_object()\ .keyval('version', '0.1.0')\ - .keyval('attribution', OSM_ATTRIBUTION)\ + .keyval('attribution', cl.OSM_ATTRIBUTION)\ .keyval('licence', 'ODbL')\ .keyval_not_none('query', options.get('query'))\ .end_object().next()\ .key('features').start_array() for result in results: - if result.address_rows: - label_parts = result.address_rows.localize(locales) - else: - label_parts = [] - out.start_object()\ .keyval('type', 'Feature')\ .key('properties').start_object()\ @@ -245,9 +236,9 @@ def format_base_geocodejson(results: napi.ReverseResults, out.keyval('osm_key', result.category[0])\ .keyval('osm_value', result.category[1])\ .keyval('type', GEOCODEJSON_RANKS[max(3, min(28, result.rank_address))])\ - .keyval_not_none('accuracy', result.distance)\ - .keyval('label', ', '.join(label_parts))\ - .keyval_not_none('name', locales.display_name(result.names))\ + .keyval_not_none('accuracy', getattr(result, 'distance', None), transform=int)\ + .keyval('label', result.display_name or '')\ + .keyval_not_none('name', result.locale_name or None)\ if options.get('addressdetails', False): _write_geocodejson_address(out, result.address_rows, result.place_id, @@ -256,7 +247,8 @@ def format_base_geocodejson(results: napi.ReverseResults, out.key('admin').start_object() if result.address_rows: for line in result.address_rows: - if line.isaddress and (line.admin_level or 15) < 15 and line.local_name: + if line.isaddress and (line.admin_level or 15) < 15 and line.local_name \ + and line.category[0] == 'boundary' and line.category[1] == 'administrative': out.keyval(f"level{line.admin_level}", line.local_name) out.end_object().next()