Archivio

Posts Tagged ‘OpenRefine’

OpenStreetMap, GeoPortale Nazionale e OpenRefine: tutorial per come farsi del geocoding in casa partendo da un elenco di indirizzi


Partendo dal mio ultimo post “Come convertire indirizzi in coordinate geografiche (geocoding) usando i servizi WFS del GeoPortale Nazionale e Open Refine“, che ha tratto ispirazione da quest’altro post “Using OpenRefine to geocode your data with Google and OpenStreetMap API”, ho provato a mettere insieme le cose per cercare di ottenere una sorta di “guida” su come, partendo da un foglio elettronico in  cui vi siano dei dati da georiferire per indirizzo, ottenerne la georeferenziazione, con la migliore precisione possibile e al più approssimata  al Comune.

Ecco quali sono i criteri che ho provato a seguire:

  1. se il dato è possibile georiferirlo usando i dati di OpenStreetMap e quindi le  MapQuest Nominatim API, questa viene considerata la prima e migliore delle opzioni: occorre tuttavia appurare che la georeferenziazione avvenga per “osm_type=node”, e quindi per punto. Sostanzialmente se quello specifico numero civico esiste tra i dati di OpenStreetMap, questo viene considerato il dato migliore
  2. se il dato non è georiferibile usando i dati di OpenStreetMap e quindi le  MapQuest Nominatim API per “nodo”, si verifica se lo sia usando i servizi WFS del GeoPortale Nazionale: se lo è viene questa viene considerata come seconda opzione
  3. se il dato non è georiferibile usando i dati di OpenStreetMap e quindi le  MapQuest Nominatim API per “nodo”, e nemmeno usando i servizi WFS del GeoPortale Nazionale, si verifica se lo sia usando i dati di OpenStreetMap e quindi le API di Nominatim per “osm_type=way”, e quindi per interpolazione sulla strada: se lo è viene questa viene considerata come terza opzione
  4. se il bene non è georiferibile nè usando i dati di OpenStreetMap e quindi le  MapQuest Nominatim API per “nodo”, nè usando i servizi WFS del GeoPortale Nazionale, e nemmeno usando i dati di OpenStreetMap e quindi le  MapQuest Nominatim API per “osm_type=way”, si verifica se lo sia usando e API di Nominatim georeferendo per Comune: se lo è (e lo dovrebbe essere sempre …..), viene questa viene considerata come quarta opzione ovviamente con un grado di approssimazione molto elevato e grossolano.

In questo modo, classificando la tipologia di metodo di georeferenziazione, possiamo differenziare per  la “qualità” della precisione con cui quel dato è stato georiferito per indirizzo.

Come detto in precedenza si ipotizza di partire da un foglio elettronico che contenga i dati da georiferire. La sua struttura dati può essere libera: nel seguito si indicheranno quali sono i nuovi campi da creare che, al termine delle operazioni potranno essere eliminati, lasciando i soli campi contenenti le coordinate degli indirizzi e la tipologia di modalità di geocodifica.

  1. aprire il foglio elettronico in Google Refine / Open Refine e generare un progetto
  2. creare una colonna con nome “Comune-work-1” contenente il nome del comune
  3. creare una colonna con nome “Comune-work-2” partendo dalla colonna “Comune-work-1” applicando la formula replace(value,' ','%20')
  4. modificare il contenuto della colonna “Comune-work-2” applicando la formula replace(value,'\'','%27'). NOTA: se nel nome del comune compaiono altro caratteri particolari, replicare sostituendo le rispettive sequenze di escape.
  5. creare una colonna con nome “Ubicazione-work-1” contenente la ubicazione (es. Via Roma), SENZA civico
  6. creare una colonna “Ubicazione-work-2” partendo dalla colonna “Ubicazione-work-1” eliminando gli spazi sostituendoli con il carattere di escape %20, eliminando gli apostrofi sotituendoli con il carattere di escape %27, ecc … Occorre lavorare un pò direttamente in Refine: se non ci sono info o se ci sono info non corrette mettere come valore “xxx”
  7. creare una colonna con nome “Civico-work-1” contenente il SOLO numero civico. Occorre lavorare un pò in Excel o Refine: se non ci sono info o se ci sono info non corrette mettere “xxx”
  8. creare una colonna “ResponsePCN” il cui contenuto è il risultato delle query WFS al PCN, fatte ogni 1500 millisecondi (o superiore …) ottenute da 'http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&VERSION=1.1.0&service=wfs&request=GetFeature&TYPENAME=IN.NUMERICIVICI.2012&Filter=%3Cogc:Filter%20xmlns:ogc=%22http://www.opengis.net/ogc%22%3E%3CAND%3E%3Cogc:PropertyIsEqualTo%20matchCase=%22false%22%3E%3Cogc:PropertyName%3Ecomune%3C/ogc:PropertyName%3E%3Cogc:Literal%3E' + cells["Comune-work-2"].value + '%3C/ogc:Literal%3E%3C/ogc:PropertyIsEqualTo%3E%3Cogc:PropertyIsEqualTo%20matchCase=%22false%22%3E%3Cogc:PropertyName%3Enome%3C/ogc:PropertyName%3E%3Cogc:Literal%3E' + cells["Ubicazione-work-2"].value + '%3C/ogc:Literal%3E%3C/ogc:PropertyIsEqualTo%3E%3Cogc:PropertyIsLike%20matchCase=%22false%22%20wildCard=%22*%22%20singleChar=%22.%22%20escapeChar=%22!%22%3E%3Cogc:PropertyName%3Ecivico%3C/ogc:PropertyName%3E%3Cogc:Literal%3E*' + cells["Civico-work-1"].value + '*%3C/ogc:Literal%3E%3C/ogc:PropertyIsLike%3E%3C/AND%3E%3C/ogc:Filter%3E'
  9. creare una colonna “Lat-PCN” partendo dalla colonna “ResponsePCN” ed applicare la seguente regola: toNumber(split(trim(substring(value.parseHtml().select("gml|Point gml|pos")[0].toString(),10, -10)), " ")[0])
  10. creare una colonna “Lon-PCN” partendo dalla colonna “ResponsePCN” ed applicare la seguente regola: toNumber(split(trim(substring(value.parseHtml().select("gml|Point gml|pos")[0].toString(),10, -10)), " ")[1])
  11. usare le facets “Text” sulla colonna “Lat-PCN“: selezionare le righe “blank” e valorizzare a 0
  12. usare le facets “Text” sulla colonna “Lon-PCN“: selezionare le righe “blank” e valorizzare a 0
  13. creare una colonna “AddressForOsmNominatim” da valorizzare con la seguente regola: cells["Ubicazione-work-2"].value + "%20" + cells["Civico-work-1"].value + "," + cells["Comune-work-2"].value + ",Italia"
  14. creare una colonna “ResponseNominatimForAddress” il cui contenuto è il risultato della query a Nominatim con la seguente chiamata: 'http://open.mapquestapi.com/nominatim/v1/search.php?format=json&q=' + cells["AddressForOsmNominatim"].value
  15. creare una colonna “Lat-OSM-Address-Node” partendo dalla colonna “ResponseNominatimForAddress” ed applicare la seguente regola: if(value.parseJson()[0].osm_type=="node",value.parseJson()[0].lat,"")
  16. usare le facets “Text” sulla colonna “Lat-OSM-Address-Node“: selezionare le righe “blank” e valorizzare a 0
  17. creare una colonna “Lon-OSM-Address-Node” partendo dalla colonna “ResponseNominatimForAddress” ed applicare la seguente regola: if(value.parseJson()[0].osm_type=="node",value.parseJson()[0].lon,"")
  18. usare le facets “Text” sulla colonna “Lon-OSM-Address-Node“: selezionare le righe “blank” e valorizzare a 0
  19. creare una colonna “Lat-OSM-Address-Way” partendo dalla colonna “ResponseNominatimForAddress” ed applicare la seguente regola: if(value.parseJson()[0].osm_type=="way",value.parseJson()[0].lat,"")
  20. usare le facets “Text” sulla colonna “Lat-OSM-Address-Way“: selezionare le righe “blank” e valorizzare a 0
  21. creare una colonna “Lon-OSM-Address-Way” partendo dalla colonna “ResponseNominatimForAddress” ed applicare la seguente regola: if(value.parseJson()[0].osm_type=="way",value.parseJson()[0].lon,"")
  22. usare le facets “Text” sulla colonna “Lon-OSM-Address-Way“: selezionare le righe “blank” e valorizzare a 0
  23. creare una colonna “CityForOsmNominatim” e valorizzare con la seguente regola: cells["Comune-work-2"].value + ",Italia&limit=1"
  24. creare una colonna “ResponseNominatimForCity” il cui contenuto è il risultato della query a Nominatim con la seguente chiamata: 'http://open.mapquestapi.com/nominatim/v1/search.php?format=json&q=' + cells["CityForOsmNominatim"].value
  25. creare una colonna “Lat-OSM-City” partendo dalla colonna “ResponseNominatimForCity” ed applicare la seguente regola: value.parseJson()[0].lat
  26. usare le facets “Text” sulla colonna “Lat-OSM-City“: selezionare le righe “blank” e valorizzare a 0
  27. creare una colonna “Lon-OSM-City” partendo dalla colonna “ResponseNominatimForCity” ed applicare la seguente regola: value.parseJson()[0].lon
  28. usare le facets “Text” sulla colonna “Lon-OSM-City“: selezionare le righe “blank” e valorizzare a 0
  29. creare una colonna “GeoRefType” e valorizzare cona la seguente regola: if(cells["Lon-OSM-Address-Node"].value!="0","OSM_NODE",(if(cells["Lon-PCN"].value!="0","GN",(if(cells["Lon-OSM-Address-Way"].value!="0","OSM-WAY","OSM-CITY")))))
  30. creare una colonna “Lat” e valorizzare cona la seguente regola: if(cells["Lat-OSM-Address-Node"].value!="0",cells["Lat-OSM-Address-Node"].value,(if(cells["Lat-PCN"].value!="0",cells["Lat-PCN"].value,(if(cells["Lat-OSM-Address-Way"].value!="0",cells["Lat-OSM-Address-Way"].value,cells["Lat-OSM-City"].value)))))
  31. creare una colonna “Lon” e valorizzare cona la seguente regola: if(cells["Lon-OSM-Address-Node"].value!="0",cells["Lon-OSM-Address-Node"].value,(if(cells["Lon-PCN"].value!="0",cells["Lon-PCN"].value,(if(cells["Lon-OSM-Address-Way"].value!="0",cells["Lon-OSM-Address-Way"].value,cells["Lon-OSM-City"].value)))))
  32. applicare la trasformazione “To number” alle celle della colonna “Lat
  33. applicare la trasformazione “To number” alle celle della colonna “Lon
  34. cancellare, se desiderato, tutte le colonne di lavoro mantenendo solo le colonne “GeoRefType“, “Lat” e “Lon

Quanto descritto sopra ha valenza generale e può essere modificato a piacere, sia alterando i criteri utilizzati per dare le priorità di georeferenziazione tra le diverse alternative, sia, qualora si individuassero altri servizi WFS di esposizione dei numeri civici georiferiti in aggiunta a quelli del GeoPortale Nazionale, per estendere le fonti utilizzate.

A questo punto non vi resta che provare con dei vostri dati (se ci sono errori o cose non chiare segnalate e chiedete …. proviamo a risolvere insieme), e mettere così le vostre informazioni, delle quali al momento avete solo un indirizzo, su una qualunque mappa desideriate.

Enjoy!

 

Come convertire indirizzi in coordinate geografiche (geocoding) usando i servizi WFS del GeoPortale Nazionale e Open Refine

29 Maggio 2015 9 commenti

Quante volte si ha la necessità di convertire un indirizzo nella corrispondente coppia di cooordinate e quindi,  in un dato spaziale riutilizzabile?

E quante volte si avrebbe la necessità di  farlo su un insieme di indirizzi?

E quanti dati si potrebbero georiferire per indirizzo, portandoli inizialmente su una mappa, per poi usarli ed analizzarli con funzionalità “spaziali” incrociandoli con altri dati georiferiti?

Certo, a queste domande si potrebbe rispondere (e spesso si opera in tal modo ….), dicendo ” …. ma ci sono i servizi di geocoding di Google (o similari)!!“.

Vero, cosa buona e giusta, non si fà peccato, e chissà quante volte questi sono stati (e saranno …), utilizzati anche da coloro che abitualmente lavorano con i dati spaziali, compreso chi sta scrivendo questo post.

Però è altrettanto vero che esistono modalità alternative le quali possono fare uso di open data o open services pubblicamente disponibili.

Semplicemente ……. è meno noto e quindi non le si utilizza, sprecando piccole o grandi miniere che sono state faticosamente messe pubblicamente disponibili a tutti, e che quindi sono a tutti gli effetti ……”roba” nostra!

Con queste modalità è inoltre possibile evitare i limiti di licenza che si devono, professionalmemte, rispettare qualora si utilizzino le modalità di geocoding che si avvalgono, ad esempio, delle Google Geocoding API che riporto, per sintesi e chiarezza, in modo integrale (qui il link per il riferimento ufficiale completo) :

==================================================================================================

The Google Geocoding API has the following limits in place:

Users of the free API:
  • 2500 requests per 24 hour period.
  • 5 requests per second.
Google Maps API for Work customers:
  • 100 000 requests per 24 hour period.
  • 10 requests per second.

Note: These limits apply to the Google Geocoding web service which is primarily intended for server-side geocoding. If you are geocoding data in response to user input on the web, or on a mobile device, consider using client side geocoding.

These limits are enforced to prevent abuse and/or repurposing of the Geocoding API, and may be changed in the future without notice. Additionally, we enforce a request rate limit to prevent abuse of the service. If you exceed the 24-hour limit or otherwise abuse the service, the Geocoding API may stop working for you temporarily. If you continue to exceed this limit, your access to the Geocoding API may be blocked.

For guidance on strategies for optimizing quota usage, please refer to Usage Limits for Google Maps API Web Services and Geocoding Strategies.

The Geocoding API may only be used in conjunction with a Google map; geocoding results without displaying them on a map is prohibited. For complete details on allowed usage, consult the Maps API Terms of Service License Restrictions.

==================================================================================================

La frase The Geocoding API may only be used in conjunction with a Google map è fortemente vincolante e, sinceramente, non so quanto sia nota e rispettata.

Questo non vuol dire che gli open data, o gli open services, sui civici georiferiti siano liberamente utilizzabili e siano privi di licenza, tutt’altro: hanno anch’essi le loro, spesso e volentieri non sono le licenze più “permissive” come potrebbe essere una Creative Commons — CC0 1.0 Universal, ma al tempo stesso spesso permettono, nei rispetto delle stesse, un utilizzo più ampio dei dati georiferiti rispetto ad esempio a quelle di BigG .

Partendo da questi presupposti e avendo ad esempio ipotetico una serie di informazioni, magari su un documento testuale o un foglio elettronico, per le quali si abbiano gli indirizzi comprensivi di nome comune, via e numero civico, cosa serve quindi per poter essere operativi ?

Direi che servono potenzialmente due cose (oltre ad un pò di pazienza e la voglia di sporcarsi un pò le mani ….):

  • degli open data relativi ai civici georiferiti
  • degli open services relativi ai civici che permettano di essere interrogati per indirizzo restituendo, possibilmente in un formato standard,  le rispettive coordinate in un qualche sistema di riferimento

Sul primo punto direi che mi sono già espresso e trovate riferimenti in proposito in altri post in questo stesso blog: la P.A si stà pian piano muovendo (un pò in ordine sparso a dire il vero ….), sulla base di questo stò, faticosamente, cercando di mantenere una raccolta di quelli che sono gli open data sui civici ad oggi disponibili sul territorio  nazionale ed esisterebbe anche la teorica disponibilità dei civici georiferiti open data prevista nell’elenco dei dataset dell’Agenda Digitale 2014, purtroppo al momento ampiamente disattesa.

Sul secondo, che è quello di maggior interesse per gli obiettivi di questo post, non esistono molti open services che permettano di fare un geocoding, ma, fortunamente, in questo caso viene in aiuto il GeoPortale Nazionale e, per la precisione, il servizio WFS dei civici, nello specifico denominato Numeri civici – Aggiornamento 2012. 

Per tale servizio sono resi disponibili:

NOTA: ovviamente dello stesso dataset esiste anche il servizio WMS che trovate, con lo stesso nome, in questo elenco http://www.pcn.minambiente.it/PCNDYN/catalogowms.jsp?lan=it

Le opportunità che tale servizio offre sono:

  • implementazione secondo protocolli di interoperabilità standard (WFS)
  • intera copertura nazionale

E’ quindi possibile, potenzialmente, inviare una richiesta WFS al servizio facendosi restituire le features che soddisfano alle condizioni di richiesta: sono restitituiti tutti i dati relativi alle features stesse, comprese le geometrie e quindi si possono ottenere le coordinate di un qualunque indirizzo sul territorio nazionale.

Nella pratica, andando poi a vedere nel dettaglio, non è detto che ci siano tutti tutti gli indirizzi, ma ci si augura che la copertura, come anche la qualità dell’informazione, sia in continua crescita.

La disponibilità di un tale servizio è comunque, e sicuramente, elemento prezioso e tanto vale provare ad usarlo.

La prima cosa da fare è sapere quelle che sono le caratteristiche (metadati), del servizio e queste le si possono ottenere con la seguente chiamata al servizio wfs:

http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&service=wfs&request=getCapabilities

Il secondo passo è sapere come è strutturata l’informazione associata, questo per individuare i campi su cui elaborare la richiesta: questo lo si può ottenere con la seguente chiamata al servizio wfs:

http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&service=wfs&request=DescribeFeatureType

A questo punto è possibile elaborare la query: un esempio è il seguente (l’indirizzo ricercato è Berbenno, Via Milano 55):

http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&VERSION=1.1.0&service=wfs&request=GetFeature&TYPENAME=IN.NUMERICIVICI.2012&Filter=<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><AND><ogc:PropertyIsEqualTo matchCase="false"><ogc:PropertyName>comune</ogc:PropertyName><ogc:Literal>Berbenno</ogc:Literal></ogc:PropertyIsEqualTo><ogc:PropertyIsEqualTo matchCase="false"><ogc:PropertyName>nome</ogc:PropertyName><ogc:Literal>Via Milano</ogc:Literal></ogc:PropertyIsEqualTo><ogc:PropertyIsLike matchCase="false" wildCard="*" singleChar="." escapeChar="!"><ogc:PropertyName>civico</ogc:PropertyName><ogc:Literal>*55*</ogc:Literal></ogc:PropertyIsLike></AND></ogc:Filter>

la quale produce il seguente risultato (in evidenza la porzione di XML in cui vi sono le coordinate del punto)

<?xml version='1.0' encoding="ISO-8859-1" ?>
 <wfs:FeatureCollection
 xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
 xmlns:gml="http://www.opengis.net/gml"
 xmlns:wfs="http://www.opengis.net/wfs"
 xmlns:ogc="http://www.opengis.net/ogc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=IN.NUMERICIVICI.2012&amp;OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:4326">
 <gml:lowerCorner>45.808287 9.575815</gml:lowerCorner>
 <gml:upperCorner>45.808287 9.575815</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <gml:featureMember>
 <ms:IN.NUMERICIVICI.2012 gml:id="IN.NUMERICIVICI.2012.1225789">
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:4326">
 <gml:lowerCorner>45.808287 9.575815</gml:lowerCorner>
 <gml:upperCorner>45.808287 9.575815</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <ms:boundary>
 <gml:Point srsName="EPSG:4326">
 <gml:pos>45.808287 9.575815</gml:pos>
 </gml:Point>
 </ms:boundary>
 <ms:id>13800026062251</ms:id>
 <ms:nome>Via Milano</ms:nome>
 <ms:civico>55</ms:civico>
 <ms:istat>03016023</ms:istat>
 <ms:cap>24030</ms:cap>
 <ms:comune>BERBENNO</ms:comune>
 <ms:nome_ted> </ms:nome_ted>
 <ms:provincia>BERGAMO</ms:provincia>
 <ms:regione>LOMBARDIA</ms:regione>
 </ms:IN.NUMERICIVICI.2012>
 </gml:featureMember>
 </wfs:FeatureCollection>

Nota tecnica solo per chi interessato: analizzando il contenuto del filtro WFS della richiesta si può notare che abbiamo tre condizioni in AND: in due casi si usa l’operatore ogc:PropertyIsEqualTo mentre in uno si usa invece l’operatore ogc:PropertyIsLike.

<AND>
 <ogc:PropertyIsEqualTo matchCase="false">
 <ogc:PropertyName>comune</ogc:PropertyName>
 <ogc:Literal>Berbenno</ogc:Literal>
 </ogc:PropertyIsEqualTo>
 <ogc:PropertyIsEqualTo matchCase="false">
 <ogc:PropertyName>nome</ogc:PropertyName>
 <ogc:Literal>Via Milano</ogc:Literal>
 </ogc:PropertyIsEqualTo>
 <ogc:PropertyIsLike matchCase="false" wildCard="*" singleChar="." escapeChar="!">
 <ogc:PropertyName>civico</ogc:PropertyName>
 <ogc:Literal>*55*</ogc:Literal>
 </ogc:PropertyIsLike>
</AND>

La ragione è legata al fatto che MapServer (che è l’application server GIS utilizzato dal GeoPortale Nazionale per esporre i servizi di interoperabilità OGC compliant), ha delle difficoltà a trattare numeri espressi come stringhe e quindi occorre necessariamente usare questo workaround: il dettaglio è trattato qui: http://osgeo-org.1560.x6.nabble.com/How-to-use-filter-encoding-in-MapServer-in-a-WFS-query-td5205424.html

 A questo punto quello che resta da fare sono due ulteriori passi:

  • automatizzare le richieste nel caso, tipico, di un elenco / insieme di dati geroriferiti per indirizzo
  • estrarre le coordinate dei civici così georiferiti dall’XML di risposta

Per entrambi può tornare utile come tool Open Refine da un lato, e le preziose indicazioni di questo post “Using OpenRefine to geocode your data with Google and OpenStreetMap API” da cui ho preso spunto ed ispirazione dopo aver assistito al mini-corso della sezione di  “da UglyData a Mappa in un pomeriggio: passando per OpenRefine, R e Turf.JS” (tenuto da Simone Cortesi, Andrea Zedda, Michele Ferretti e con la partecipazione di Fabrizio Tambussa e Stefano Sabatini che ringrazio in blocco…..), svoltosi nella giornata di chiusura del raduno Spaghetti Open Data 2015 (SOD15) a Bologna.

Il post di cui sopra illustra come fare geocoding usando i servizi di geocoding  Google Maps e OpenStreetMap, nello specifico MapQuest Nominatim API: ho pensato di provare ad estenderlo usando come servizio di geocoding il servizio WFS dei civici del GeoPortale Nazionale.

Premessa: non descrivo qui nel dettaglio come usare OpenRefine, è out-of-scope di questo post. Sulla rete è disponibile ampio materiale illustrativo e tutorial per muovere i primi passi.

Immaginiamo di partire da un foglio elettronico in cui vi siano i dati da georiferire con le informazioni di Comune, Via e Numero Civico, sommate ovviamente ad altre informazioni descrittive.

La prima cosa da fare, dopo aver ovviamente caricato il foglio elettronico in OpenRefine, è preparare i dati in modo che Comune, Via e Numero Civico siano rispettivamente su tre colonne separate che chiameremo “Comune“, “Ubicazione” e “Civico“, e che, qualora vi siano degli spazi, questi siano sostituiti dalla corrispondente sequenza di escape %20, se compaiono apostrofi questi siano sostituiti dalla corrispondente sequenza di escape %27, ecc … (questa operazione può essere fatta a mano o usando le funzionalità di OpenRefine).

A questo punto è necessario aggiungere una nuova colonna selezionando una colonna esistente e cliccando il tasto destro del mouse selezionando Edit column –>Add column by fetching URLs.

Nella nuova colonna che ad esempio chiameremo “PCN”, copiare la seguente chiamata http in GET parametrizzata:

'http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&VERSION=1.1.0&service=wfs&request=GetFeature&TYPENAME=IN.NUMERICIVICI.2012&Filter=%3Cogc:Filter%20xmlns:ogc=%22http://www.opengis.net/ogc%22%3E%3CAND%3E%3Cogc:PropertyIsEqualTo%20matchCase=%22false%22%3E%3Cogc:PropertyName%3Ecomune%3C/ogc:PropertyName%3E%3Cogc:Literal%3E' + cells["Comune"].value + '%3C/ogc:Literal%3E%3C/ogc:PropertyIsEqualTo%3E%3Cogc:PropertyIsEqualTo%20matchCase=%22false%22%3E%3Cogc:PropertyName%3Enome%3C/ogc:PropertyName%3E%3Cogc:Literal%3E' + cells["Ubicazione"].value + '%3C/ogc:Literal%3E%3C/ogc:PropertyIsEqualTo%3E%3Cogc:PropertyIsLike%20matchCase=%22false%22%20wildCard=%22*%22%20singleChar=%22.%22%20escapeChar=%22!%22%3E%3Cogc:PropertyName%3Ecivico%3C/ogc:PropertyName%3E%3Cogc:Literal%3E*' + cells["Civico"].value + '*%3C/ogc:Literal%3E%3C/ogc:PropertyIsLike%3E%3C/AND%3E%3C/ogc:Filter%3E'

Quando si procederà, confermando, saranno inviate tante chiamate in GET quante sono le righe del foglio elettronico e per ognuna verrà mantenuto l’XML di risposta: per l’indirizzo in esame ecco l’XML risultato della chiamata con evidenziati i campi che contengono le coordinate dell’indirizzo

<?xml version='1.0' encoding="ISO-8859-1" ?>
 <wfs:FeatureCollection
 xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
 xmlns:gml="http://www.opengis.net/gml"
 xmlns:wfs="http://www.opengis.net/wfs"
 xmlns:ogc="http://www.opengis.net/ogc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=IN.NUMERICIVICI.2012&amp;OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:4326">
 <gml:lowerCorner>45.808287 9.575815</gml:lowerCorner>
 <gml:upperCorner>45.808287 9.575815</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <gml:featureMember>
 <ms:IN.NUMERICIVICI.2012 gml:id="IN.NUMERICIVICI.2012.1225789">
 <gml:boundedBy>
 <gml:Envelope srsName="EPSG:4326">
 <gml:lowerCorner>45.808287 9.575815</gml:lowerCorner>
 <gml:upperCorner>45.808287 9.575815</gml:upperCorner>
 </gml:Envelope>
 </gml:boundedBy>
 <ms:boundary>
 <gml:Point srsName="EPSG:4326">
 <gml:pos>45.808287 9.575815</gml:pos>
 </gml:Point>
 </ms:boundary>
 <ms:id>13800026062251</ms:id>
 <ms:nome>Via Milano</ms:nome>
 <ms:civico>55</ms:civico>
 <ms:istat>03016023</ms:istat>
 <ms:cap>24030</ms:cap>
 <ms:comune>BERBENNO</ms:comune>
 <ms:nome_ted> </ms:nome_ted>
 <ms:provincia>BERGAMO</ms:provincia>
 <ms:regione>LOMBARDIA</ms:regione>
 </ms:IN.NUMERICIVICI.2012>
 </gml:featureMember>
 </wfs:FeatureCollection>

Per evitare di sovraccaricare il server di chiamate (ed essere magari “bannati” dal GeoPortale …..), occorre essere professionali: la disponibilità di un servizio non ne implica un abuso e quindi è doveroso, ed opportuno, schedulare le chiamate verso il server in modo che siano sufficientemente distanziate nel tempo.

Open Refine lo permette di fare impostando un parametro “Throttle delay” quando si crea una colonna Add column by fetching URLs.

ThrottleDelay

Di default tale parametro è valorizzato a 5000 millisecondi ed è quindi opportuno aumentarlo così da ridurre il carico di richieste verso il server

Una volta ottenute le  diverse risposte, una per ogni riga del nostro foglio elettronico, quello che resta da fare è estrarre dall’XML le coordinate e riportarle in campi della tabella creati appositamente.

E’ quindi possibile creare due nuove colonne partendo dalla colonna “PCN”, rispettivamente “Lat” e “Lon”, per ognuna delle quali si dovranno applicare le seguenti regole espresse in linguaggio GREL:

  • toNumber(split(trim(substring(value.parseHtml().select(“gml|Point gml|pos”)[0].toString(),10, -10)), ” “)[0])
  • toNumber(split(trim(substring(value.parseHtml().select(“gml|Point gml|pos”)[0].toString(),10, -10)), ” “)[1])

Terminate queste attività è quindi possibile eliminare, se ritenute non più utili, tutte le colonne di servizio: quello che si otterrà è lo stesso foglio elettronico iniziale con due nuove colonne “Lat” e “Lon” in cui saranno valorizzate le coordinate dell’indirizzo (questo se la chiamata al servizio del GeoPortale ha dato esito positivo, quindi per un indirizzo presente nella base dati, altrimenti ovviamente non avremmo alcun valore).

Tutto sommmato piuttosto semplice rispetto al grosso valore aggiunto che si ottiene: buon divertimento!