Closed mtrakal closed 1 year ago
Thank you for your suggestion @mtrakal! We will have a look, for Android specifically after 15 Dec.
cc @DzmitryFomchyn @sarochych
Hey @mtrakal,
It's reflected on public API / playground, but not in SDK.
Could you please clarify what do you mean here? Few examples will be helpful. Also, which API type you are using, v5 or SBS?
As you can see, there are 3 different types how address is formatted.
I'm not sure if this is official standard. Other sources say a slightly different formatting rules for some countries.
Anyway, I'm still not sure if this should be part of SDK unless we guarantee correct formatting. Search SDK provides address components and customers can format address in required order.
More info what we are using and what is inconsistency between SDK and API in some old issues sample here: https://github.com/mtrakal/mapbox-issues
Search in Readme for:
Another thing is, that formatter doesn't respect the national format of address (but API respects it). and below is description for reported issue here.
API: https://docs.mapbox.com/playground/geocoding/?search_text=Bo%C5%99ivojova%2085&country=cz%2Csk%2Cpl&limit=10&types=place%2Cpostcode%2Caddress%2Cpoi&language=cs&access_token=pk.xxx
used as referrence.
Any address in Czech Republic.
Just provide consistent data (and preferred same data as API - like place_name_cs / place_name
- a complete name with address and all will be fine. If it will return proper address in selected locale.
For now I must do this mess in code just to show proper / nice address name:
import com.mapbox.search.result.SearchAddress
import com.mapbox.search.result.SearchResult
import com.mapbox.search.result.SearchResultType
import com.mapbox.search.result.SearchSuggestion
import com.mapbox.search.result.SearchSuggestionType
val SearchResult.fullAddress: String
get() = when (types.firstByType()) {
SearchResultType.COUNTRY -> withName(address?.countryAddress) // usa
SearchResultType.REGION -> withName(address?.regionAddress) // Liberecký kraj
SearchResultType.POSTCODE,
SearchResultType.BLOCK -> withName(address?.postcodeAddress) // 468 22
SearchResultType.DISTRICT -> address?.districtAddress //
SearchResultType.PLACE -> withName(address?.placeAddress) // Praha
SearchResultType.LOCALITY -> withName(address?.localityAddress) // Manhattan / Písek Líšťany
SearchResultType.NEIGHBORHOOD -> address?.neighborhoodAddress // ?
SearchResultType.STREET -> address?.streetAddress // never used, SDK return error, if try to use STREET 🤦
SearchResultType.ADDRESS -> address?.houseAddress // any czech street is returned as address 🤷
SearchResultType.POI -> withName(address?.poiAddress) // Cross club
null -> null
}.orEmpty()
.distinct()
.filter { it.isNotBlank() }
.joinToString(", ")
.trim()
/**
* Add name of suggestion, because address don't contains this info in some cases...
*/
private fun SearchResult.withName(address: List<String>?) = listOfNotNull(name) + address.orEmpty()
val SearchSuggestion.fullAddress: String
get() = when (this.type.getSearchSuggestionType()) {
SearchResultType.COUNTRY -> withName(address?.countryAddress) // usa
SearchResultType.REGION -> withName(address?.regionAddress) // Liberecký kraj
SearchResultType.POSTCODE,
SearchResultType.BLOCK -> withName(address?.postcodeAddress) // 468 22
SearchResultType.DISTRICT -> address?.districtAddress //
SearchResultType.PLACE -> withName(address?.placeAddress) // Praha
SearchResultType.LOCALITY -> withName(address?.localityAddress) // Manhattan / Písek Líšťany
SearchResultType.NEIGHBORHOOD -> address?.neighborhoodAddress // ?
SearchResultType.STREET -> address?.streetAddress // never used, SDK return error, if try to use STREET 🤦
SearchResultType.ADDRESS -> address?.houseAddress // any czech street is returned as address 🤷
SearchResultType.POI -> withName(address?.poiAddress) // Cross club
null -> null
}.orEmpty()
.distinct()
.filter { it.isNotBlank() }
.joinToString(", ")
.trim()
/**
* Add name of suggestion, because address don't contains this info in some cases...
*/
private fun SearchSuggestion.withName(address: List<String>?) = listOfNotNull(name) + address.orEmpty()
/**
* Generally recognized countries or, in some cases like Hong Kong, an area of quasi-national
* administrative status that has been given a designated country code under ISO 3166-1.
*/
private val SearchAddress.countryAddress: List<String>
get() = listOfNotNull(country)
/**
* Top-level sub-national administrative features, such as states in the United States
* or provinces in Canada or China.
*/
private val SearchAddress.regionAddress: List<String>
get() = listOfNotNull(region, country)
/**
* Postal codes used in country-specific national addressing systems.
*/
private val SearchAddress.postcodeAddress: List<String>
get() = listOfNotNull(postcode, place, region)
/**
* Features that are smaller than top-level administrative features but typically larger than cities,
* in countries that use such an additional layer in postal addressing (for example, prefectures in China).
*/
private val SearchAddress.districtAddress: List<String>
get() = listOfNotNull(district, postcode, region)
/**
* Typically these are cities, villages, municipalities, etc.
* They’re usually features used in postal addressing, and are suitable for display in ambient
* end-user applications where current-location context is needed (for example, in weather displays).
*/
private val SearchAddress.placeAddress: List<String>
get() = listOfNotNull(place, district, postcode, region)
/**
* Official sub-city features present in countries where such an additional administrative layer
* is used in postal addressing, or where such features are commonly referred to in local parlance.
* Examples include city districts in Brazil and Chile and arrondissements in France.
*/
private val SearchAddress.localityAddress: List<String>
get() = listOfNotNull(locality, place, district, postcode, region)
/**
* Colloquial sub-city features often referred to in local parlance.
* Unlike locality features, these typically lack official status and may lack universally agreed-upon boundaries.
*/
private val SearchAddress.neighborhoodAddress: List<String>
get() = listOfNotNull(neighborhood, locality, place, district, postcode, region)
/**
* Features that are smaller than places and that correspond to streets in cities, villages, etc.
*/
private val SearchAddress.streetAddress: List<String>
get() = listOfNotNull(street, neighborhood, locality, place, district, postcode, region)
/**
* Individual residential or business addresses.
*/
private val SearchAddress.houseAddress: List<String>
get() = listOfNotNull(
streetWithHouseNumber,
neighborhood,
locality,
place,
district,
postcode,
region
)
/**
* Points of interest.
* These include restaurants, stores, concert venues, parks, museums, etc.
*/
private val SearchAddress.poiAddress: List<String>
get() = listOfNotNull(
streetWithHouseNumber,
neighborhood,
locality,
place,
district,
postcode
)
private fun SearchSuggestionType.getSearchSuggestionType(): SearchResultType? = when (this) {
is SearchSuggestionType.SearchResultSuggestion -> this.types.firstByType()
is SearchSuggestionType.Category, is SearchSuggestionType.Query -> null
else -> error("Unknown SearchSuggestionType type: $this.")
}
/**
* Get most weighted type from list of [SearchResultType].
*/
private fun List<SearchResultType>.firstByType(): SearchResultType? = this.maxByOrNull { it.weight }
/**
* Ordering weight by priority (most precise address has highest weight).
*/
private val SearchResultType.weight: Int
get() = when (this) {
SearchResultType.COUNTRY -> 0
SearchResultType.REGION -> 1
SearchResultType.POSTCODE -> 2
SearchResultType.BLOCK -> 3
SearchResultType.PLACE -> 4
SearchResultType.DISTRICT -> 5
SearchResultType.LOCALITY -> 6
SearchResultType.NEIGHBORHOOD -> 7
SearchResultType.STREET -> 8
SearchResultType.ADDRESS -> 9
SearchResultType.POI -> 10
}
/**
* Format House number and Street name to most used European format (not at all EU countries).
* https://qph.cf2.quoracdn.net/main-qimg-fed2c12535f9552efa214450c4c87881
* Created issue on MapBox: https://github.com/mapbox/mapbox-search-android/issues/112
*/
private val SearchAddress.streetWithHouseNumber: String
get() = "${street.orEmpty()} ${houseNumber.orEmpty()}".trim()
How it works:
name
for addresses, which don’t have all fields filled in SearchAddress
object. In that case is used SearchResult.name
or SearchSuggestion.name
Bořivojova 11, Praha 3 (Locality), Praha (place), 1300, Praha (region), Czech Republic (country)
@mtrakal thanks for the details!
We've fixed this issue in the 1.0.0-beta.46. Now SearchSuggestion.name
/SearchResult.name
return house number and street in a correct order. Besides that we've added a new field SearchSuggestion.fullAddress
/SearchResult.fullAddress
that returns full formatted address from the backend.
I'll close this issue for now. Feel free to reopen it or create an ew one if you have more questions.
New Feature
Add regional/country specific house number / street number format. It's reflected on public API / playground, but not in SDK.
As you can see, there are 3 different types how address is formatted.
Most part of EU:
Street HouseNumber, City
(without any divider, only space) Other parts oz world (expect Russia):HouseNumber Street, City
Russia:City, Street HouseNumber
Why
Because not all of us live in USA. Because search suggestions should reflect local conventions.