"""
Helper functions for output of results in XML format.
"""
-from typing import Mapping, Any, Optional
+from typing import Mapping, Any, Optional, Union
import datetime as dt
import xml.etree.ElementTree as ET
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
+
+#pylint: disable=too-many-branches
def _write_xml_address(root: ET.Element, address: napi.AddressLines,
country_code: Optional[str]) -> None:
parts = {}
for line in address:
- 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():
ET.SubElement(root, k).text = v
ET.SubElement(root, 'country_code').text = country_code
-def _create_base_entry(result: napi.ReverseResult, #pylint: disable=too-many-branches
- root: ET.Element, simple: bool,
- locales: napi.Locales) -> ET.Element:
- if result.address_rows:
- label_parts = result.address_rows.localize(locales)
- else:
- label_parts = []
-
+def _create_base_entry(result: Union[napi.ReverseResult, napi.SearchResult],
+ root: ET.Element, simple: bool) -> ET.Element:
place = ET.SubElement(root, 'result' if simple else 'place')
if result.place_id is not None:
place.set('place_id', str(result.place_id))
if result.osm_object:
- osm_type = OSM_TYPE_NAME.get(result.osm_object[0], None)
+ osm_type = cl.OSM_TYPE_NAME.get(result.osm_object[0], None)
if osm_type is not None:
place.set('osm_type', osm_type)
place.set('osm_id', str(result.osm_object[1]))
if result.names and 'ref' in result.names:
- place.set('place_id', result.names['ref'])
- place.set('lat', str(result.centroid.lat))
- place.set('lon', str(result.centroid.lon))
+ place.set('ref', result.names['ref'])
+ elif result.locale_name:
+ # bug reproduced from PHP
+ place.set('ref', result.locale_name)
+ place.set('lat', f"{result.centroid.lat:.7f}")
+ place.set('lon', f"{result.centroid.lon:.7f}")
- bbox = bbox_from_result(result)
- place.set('boundingbox', ','.join(map(str, [bbox.minlat, bbox.maxlat,
- bbox.minlon, bbox.maxlon])))
+ bbox = cl.bbox_from_result(result)
+ place.set('boundingbox',
+ f"{bbox.minlat:.7f},{bbox.maxlat:.7f},{bbox.minlon:.7f},{bbox.maxlon:.7f}")
place.set('place_rank', str(result.rank_search))
place.set('address_rank', str(result.rank_address))
place.set('geojson', result.geometry['geojson'])
if simple:
- place.text = ', '.join(label_parts)
+ place.text = result.display_name or ''
else:
- place.set('display_name', ', '.join(label_parts))
+ place.set('display_name', result.display_name or '')
place.set('class', result.category[0])
place.set('type', result.category[1])
place.set('importance', str(result.calculated_importance()))
return place
-def format_base_xml(results: napi.ReverseResults,
+def format_base_xml(results: Union[napi.ReverseResults, napi.SearchResults],
options: Mapping[str, Any],
simple: bool, xml_root_tag: str,
xml_extra_info: Mapping[str, str]) -> str:
""" Format the result into an XML response. With 'simple' exactly one
result will be output, otherwise a list.
"""
- locales = options.get('locales', napi.Locales())
-
root = ET.Element(xml_root_tag)
root.set('timestamp', dt.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S +00:00'))
- root.set('attribution', OSM_ATTRIBUTION)
+ root.set('attribution', cl.OSM_ATTRIBUTION)
for k, v in xml_extra_info.items():
root.set(k, v)
ET.SubElement(root, 'error').text = 'Unable to geocode'
for result in results:
- place = _create_base_entry(result, root, simple, locales)
+ place = _create_base_entry(result, root, simple)
if not simple and options.get('icon_base_url', None):
- icon = ICONS.get(result.category)
+ icon = cl.ICONS.get(result.category)
if icon:
place.set('icon', icon)