I am mapping some xml to a case class and it works fine, but I have a feeling that my imperative blinkers are blinding me to a better functional solution. Can anyone suggest a better way than this:
def buildAddress(geocodeResponse: NodeSeq) : Address = {
val addressNodes = geocodeResponse \\ "address_component"
var street = " "
var town = ""
var suburb = ""
var province = ""
var country = ""
var postalCode = ""
addressNodes.foreach {node =>
val typeString = (node \ "type").head.text
if ("street_number" == typeString) {
street = (node \ "long_name").text + street
}
else if ("route" == typeString) {
street = street + (node \ "long_name").text
}
else if ("locality" == typeString) {
town = (node \ "long_name").text
}
else if ("sublocality" == typeString) {
suburb = (node \ "long_name").text
}
else if ("administrative_area_level_1" == typeString) {
province = (node \ "long_name").text
}
else if ("country" == typeString) {
country = (node \ "long_name").text
}
else if ("postal_code" == typeString) {
town = (node \ "long_name").text
}
}
Address(street,suburb,town,province,country,postalCode)
}
The xml in this case is retrieved from he Google geo-coding api, using Dispatch.
import dispatch._
def lookupAddress(lat: Double, long: Double): Address = {
val position = lat.toString + "," + long.toString
val req = url("http://maps.googleapis.com/maps/api/geocode/xml") <<? Map("latlng" -> position, "sensor" -> "true")
Http(req </> {
nodes => buildAddress(nodes)
})
}
The xml result looks like this:
<GeocodeResponse>
<status>OK</status>
<result>
<type>street_address</type>
<formatted_address>3 Louw St, Stellenbosch 7600, South Africa</formatted_address>
<address_component>
<long_name>3</long_name>
<short_name>3</short_name>
<type>street_number</type>
</address_component>
<address_component>
<long_name>Louw St</long_name>
<short_name>Louw St</short_name>
<type>route</type>
</address_component>
<address_component>
<long_name>Stellenbosch Central</long_name>
<short_name>Stellenbosch Central</short_name>
<type>sublocality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<address_component>
<long_name>7600</long_name>
<short_name>7600</short_name>
<type>postal_code</type>
</address_component>
<geometry>
<location>
<lat>-33.9403990</lat>
<lng>18.8610090</lng>
</location>
<location_type>ROOFTOP</location_type>
<viewport>
<southwest>
<lat>-33.9435466</lat>
<lng>18.8578614</lng>
</southwest>
<northeast>
<lat>-33.9372514</lat>
<lng>18.8641566</lng>
</northeast>
</viewport>
</geometry>
</result>
<result>
<type>sublocality</type>
<type>political</type>
<formatted_address>Stellenbosch Central, Stellenbosch, South Africa</formatted_address>
<address_component>
<long_name>Stellenbosch Central</long_name>
<short_name>Stellenbosch Central</short_name>
<type>sublocality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.9354048</lat>
<lng>18.8640607</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-33.9437180</lat>
<lng>18.8449199</lng>
</southwest>
<northeast>
<lat>-33.9230960</lat>
<lng>18.8778929</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-33.9437180</lat>
<lng>18.8449199</lng>
</southwest>
<northeast>
<lat>-33.9230960</lat>
<lng>18.8778929</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>postal_code</type>
<formatted_address>7599, South Africa</formatted_address>
<address_component>
<long_name>7599</long_name>
<short_name>7599</short_name>
<type>postal_code</type>
</address_component>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.9300286</lat>
<lng>18.8640607</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-33.9693080</lat>
<lng>18.8019200</lng>
</southwest>
<northeast>
<lat>-33.8700550</lat>
<lng>18.9232900</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-33.9693080</lat>
<lng>18.8019200</lng>
</southwest>
<northeast>
<lat>-33.8700550</lat>
<lng>18.9232900</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>locality</type>
<type>political</type>
<formatted_address>Stellenbosch, South Africa</formatted_address>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.9366667</lat>
<lng>18.8613889</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-34.0150869</lat>
<lng>18.7658819</lng>
</southwest>
<northeast>
<lat>-33.8782960</lat>
<lng>18.9232900</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-34.0150869</lat>
<lng>18.7658819</lng>
</southwest>
<northeast>
<lat>-33.8782960</lat>
<lng>18.9232900</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>postal_code</type>
<formatted_address>7600, South Africa</formatted_address>
<address_component>
<long_name>7600</long_name>
<short_name>7600</short_name>
<type>postal_code</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry/>
</result>
<result>
<type>administrative_area_level_3</type>
<type>political</type>
<formatted_address>Stellenbosch, South Africa</formatted_address>
<address_component>
<long_name>Stellenbosch</long_name>
<short_name>Stellenbosch</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.9405478</lat>
<lng>18.9502232</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-34.0633899</lat>
<lng>18.7083300</lng>
</southwest>
<northeast>
<lat>-33.7933599</lat>
<lng>19.2438000</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-34.0633899</lat>
<lng>18.7083300</lng>
</southwest>
<northeast>
<lat>-33.7933599</lat>
<lng>19.2438000</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>administrative_area_level_2</type>
<type>political</type>
<formatted_address>Brede River DC, South Africa</formatted_address>
<address_component>
<long_name>Brede River DC</long_name>
<short_name>Brede River DC</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.4220698</lat>
<lng>19.7591675</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-34.1172599</lat>
<lng>18.7083299</lng>
</southwest>
<northeast>
<lat>-32.1844899</lat>
<lng>21.0103399</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-34.1172599</lat>
<lng>18.7083299</lng>
</southwest>
<northeast>
<lat>-32.1844899</lat>
<lng>21.0103399</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>administrative_area_level_1</type>
<type>political</type>
<formatted_address>Western Cape, South Africa</formatted_address>
<address_component>
<long_name>Western Cape</long_name>
<short_name>WC</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-33.2277918</lat>
<lng>21.8568586</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-34.8330538</lat>
<lng>17.7575638</lng>
</southwest>
<northeast>
<lat>-30.4302599</lat>
<lng>24.2224100</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-34.8330538</lat>
<lng>17.7575638</lng>
</southwest>
<northeast>
<lat>-30.4302599</lat>
<lng>24.2224100</lng>
</northeast>
</bounds>
</geometry>
</result>
<result>
<type>country</type>
<type>political</type>
<formatted_address>South Africa</formatted_address>
<address_component>
<long_name>South Africa</long_name>
<short_name>ZA</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>-30.5594820</lat>
<lng>22.9375060</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>-34.9670000</lat>
<lng>16.2817000</lng>
</southwest>
<northeast>
<lat>-22.1253869</lat>
<lng>33.0469000</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>-34.9670000</lat>
<lng>16.2817000</lng>
</southwest>
<northeast>
<lat>-22.1253869</lat>
<lng>33.0469000</lng>
</northeast>
</bounds>
</geometry>
</result>
</GeocodeResponse>
Unless you get some kind of reflection, there really isn’t much you can do to make it better. It seems you could improve how you match your attributes, doing something like this, to help with the sheer drudgery of it: