]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/api/v1/format.py
make sure the place name always comes first in output
[nominatim.git] / nominatim / api / v1 / format.py
index 3643af83f13287efa2e26aac1e396f271f8d05d5..53156fdd41132ada43139546d36ec0e470590858 100644 (file)
@@ -7,14 +7,20 @@
 """
 Output formatters for API version v1.
 """
-from typing import Mapping, Any
+from typing import List, Dict, Mapping, Any
 import collections
+import datetime as dt
 
 import nominatim.api as napi
 from nominatim.api.result_formatting import FormatDispatcher
 from nominatim.api.v1.classtypes import ICONS
+from nominatim.api.v1 import format_json, format_xml
 from nominatim.utils.json_writer import JsonWriter
 
+class RawDataList(List[Dict[str, Any]]):
+    """ Data type for formatting raw data lists 'as is' in json.
+    """
+
 dispatch = FormatDispatcher()
 
 @dispatch.format_func(napi.StatusResult, 'text')
@@ -45,7 +51,7 @@ def _add_address_row(writer: JsonWriter, row: napi.AddressLine,
                      locales: napi.Locales) -> None:
     writer.start_object()\
             .keyval('localname', locales.display_name(row.names))\
-            .keyval('place_id', row.place_id)
+            .keyval_not_none('place_id', row.place_id)
 
     if row.osm_object is not None:
         writer.keyval('osm_id', row.osm_object[1])\
@@ -92,16 +98,16 @@ def _add_parent_rows_grouped(writer: JsonWriter, rows: napi.AddressLines,
     writer.end_object().next()
 
 
-@dispatch.format_func(napi.SearchResult, 'details-json')
-def _format_search_json(result: napi.SearchResult, options: Mapping[str, Any]) -> str:
+@dispatch.format_func(napi.DetailedResult, 'json')
+def _format_details_json(result: napi.DetailedResult, options: Mapping[str, Any]) -> str:
     locales = options.get('locales', napi.Locales())
     geom = result.geometry.get('geojson')
-    centroid = result.centroid_as_geojson()
+    centroid = result.centroid.to_geojson()
 
     out = JsonWriter()
     out.start_object()\
-         .keyval('place_id', result.place_id)\
-         .keyval('parent_place_id', result.parent_place_id)
+         .keyval_not_none('place_id', result.place_id)\
+         .keyval_not_none('parent_place_id', result.parent_place_id)
 
     if result.osm_object is not None:
         out.keyval('osm_type', result.osm_object[0])\
@@ -110,17 +116,17 @@ def _format_search_json(result: napi.SearchResult, options: Mapping[str, Any]) -
     out.keyval('category', result.category[0])\
          .keyval('type', result.category[1])\
          .keyval('admin_level', result.admin_level)\
-         .keyval('localname', locales.display_name(result.names))\
-         .keyval('names', result.names or [])\
-         .keyval('addresstags', result.address or [])\
-         .keyval('housenumber', result.housenumber)\
-         .keyval('calculated_postcode', result.postcode)\
-         .keyval('country_code', result.country_code)\
+         .keyval('localname', result.locale_name or '')\
+         .keyval('names', result.names or {})\
+         .keyval('addresstags', result.address or {})\
+         .keyval_not_none('housenumber', result.housenumber)\
+         .keyval_not_none('calculated_postcode', result.postcode)\
+         .keyval_not_none('country_code', result.country_code)\
          .keyval_not_none('indexed_date', result.indexed_date, lambda v: v.isoformat())\
-         .keyval('importance', result.importance)\
+         .keyval_not_none('importance', result.importance)\
          .keyval('calculated_importance', result.calculated_importance())\
-         .keyval('extratags', result.extratags or [])\
-         .keyval('calculated_wikipedia', result.wikipedia)\
+         .keyval('extratags', result.extratags or {})\
+         .keyval_not_none('calculated_wikipedia', result.wikipedia)\
          .keyval('rank_address', result.rank_address)\
          .keyval('rank_search', result.rank_search)\
          .keyval('isarea', 'Polygon' in (geom or result.geometry.get('type') or ''))\
@@ -135,7 +141,7 @@ def _format_search_json(result: napi.SearchResult, options: Mapping[str, Any]) -
     if result.address_rows is not None:
         _add_address_rows(out, 'address', result.address_rows, locales)
 
-    if result.linked_rows is not None:
+    if result.linked_rows:
         _add_address_rows(out, 'linked_places', result.linked_rows, locales)
 
     if result.name_keywords is not None or result.address_keywords is not None:
@@ -161,3 +167,90 @@ def _format_search_json(result: napi.SearchResult, options: Mapping[str, Any]) -
     out.end_object()
 
     return out()
+
+
+@dispatch.format_func(napi.ReverseResults, 'xml')
+def _format_reverse_xml(results: napi.ReverseResults, options: Mapping[str, Any]) -> str:
+    return format_xml.format_base_xml(results,
+                                      options, True, 'reversegeocode',
+                                      {'querystring': options.get('query', '')})
+
+
+@dispatch.format_func(napi.ReverseResults, 'geojson')
+def _format_reverse_geojson(results: napi.ReverseResults,
+                            options: Mapping[str, Any]) -> str:
+    return format_json.format_base_geojson(results, options, True)
+
+
+@dispatch.format_func(napi.ReverseResults, 'geocodejson')
+def _format_reverse_geocodejson(results: napi.ReverseResults,
+                                options: Mapping[str, Any]) -> str:
+    return format_json.format_base_geocodejson(results, options, True)
+
+
+@dispatch.format_func(napi.ReverseResults, 'json')
+def _format_reverse_json(results: napi.ReverseResults,
+                         options: Mapping[str, Any]) -> str:
+    return format_json.format_base_json(results, options, True,
+                                        class_label='class')
+
+
+@dispatch.format_func(napi.ReverseResults, 'jsonv2')
+def _format_reverse_jsonv2(results: napi.ReverseResults,
+                           options: Mapping[str, Any]) -> str:
+    return format_json.format_base_json(results, options, True,
+                                        class_label='category')
+
+
+@dispatch.format_func(napi.SearchResults, 'xml')
+def _format_search_xml(results: napi.SearchResults, options: Mapping[str, Any]) -> str:
+    extra = {'querystring': options.get('query', '')}
+    for attr in ('more_url', 'exclude_place_ids', 'viewbox'):
+        if options.get(attr):
+            extra[attr] = options[attr]
+    return format_xml.format_base_xml(results, options, False, 'searchresults',
+                                      extra)
+
+
+
+@dispatch.format_func(napi.SearchResults, 'geojson')
+def _format_search_geojson(results: napi.SearchResults,
+                            options: Mapping[str, Any]) -> str:
+    return format_json.format_base_geojson(results, options, False)
+
+
+@dispatch.format_func(napi.SearchResults, 'geocodejson')
+def _format_search_geocodejson(results: napi.SearchResults,
+                                options: Mapping[str, Any]) -> str:
+    return format_json.format_base_geocodejson(results, options, False)
+
+
+@dispatch.format_func(napi.SearchResults, 'json')
+def _format_search_json(results: napi.SearchResults,
+                         options: Mapping[str, Any]) -> str:
+    return format_json.format_base_json(results, options, False,
+                                        class_label='class')
+
+
+@dispatch.format_func(napi.SearchResults, 'jsonv2')
+def _format_search_jsonv2(results: napi.SearchResults,
+                           options: Mapping[str, Any]) -> str:
+    return format_json.format_base_json(results, options, False,
+                                        class_label='category')
+
+@dispatch.format_func(RawDataList, 'json')
+def _format_raw_data_json(results: RawDataList,  _: Mapping[str, Any]) -> str:
+    out = JsonWriter()
+    out.start_array()
+    for res in results:
+        out.start_object()
+        for k, v in res.items():
+            if isinstance(v, dt.datetime):
+                out.keyval(k, v.isoformat(sep= ' ', timespec='seconds'))
+            else:
+                out.keyval(k, v)
+        out.end_object().next()
+
+    out.end_array()
+
+    return out()