sabato 8 ottobre 2016

[C++] Esempio di utilizzo delle Open Api di Roma Servizi per la Mobilità

Roma Servizi per la Mobilità , mette a disposizione i dati della rete TPL di roma , tramite il protocollo XML-RPC .

La libreria usata in questo brutale esempio è questa, XML-RPC for C and C++ , ed è necessario compilarla e installarla prima di compilare qualsiasi client o server basato su di essa ,

l'esempio è disponibile completamente qui : https://bitbucket.org/Forzaferrarileo/esempi-c-open-api-rsm

Come prova ho preso il metodo paline.Percorsi , che restituisce i percorsi di una determinata linea , passata come argomento alla chiamata ( in questo esempio è lo 056 ) , seguendo lo schema riportato nella wiki ufficiale : Descrizione paline.Percorsi

In particolare , la chiamata prende 3 argomenti :
  1. Un token generato dall'autenticazione al server
  2. Il numero/nome della linea ( si può anche passare ad esempio MEA , MEB , MEB1 , MEC per le linee metro )
  3. un codice della lingua , utilizzato per le info ( ad esempio se la linea è disattivata )
E "ufficialmente" restituisce un dizionario così formato ( ufficialmente perchè poi nella realtà e diversa ) :
  • bool monitorata
  • bool abilitata
  • int id_news
  • array percorsi
    • string id_percorso
    • string descrizione
    • string capolinea
Cosa c'è di diverso dalla definizione alla risposta reale ?


{ id_richiesta :
   risposta {
                  monitorata
                  abilitata
                  id_news
                  percorsi [
                                  {
                                    id_percorso
                                    descrizione
                                    capolinea
                                   }
                                ]
                  }
}
la seconda cosa come si può vedere , è che l'array percorsi è formato a sua volta da n strutture contenti i vari percorsi della linea.
La terza e ultima differenza è che l'elemento "monitorata" non è un valore booleano ma intero

Passando alla parte del codice in c++  ( il file completo lo trovare in questa repo su bitbucket ) basata sul client semplice fornito come esempio nella libreria , non è altro che scomposizione della risposta nelle varie strutture e elementi elencati sopra :

Omettendo i vari header , abbiamo la richiesta di autenticazione al server di RSM :
string const authServer("http://muovi.roma.it/ws/xml/autenticazione/1");
string const authMethod("autenticazione.Accedi");
	
xmlrpc_c::clientSimple authClient;
xmlrpc_c::value result;
        
authClient.call(authServer, authMethod, "ss", &result, DEV_KEY, "");
	
string str = xmlrpc_c::value_string(result);

cout << "token: " << str << endl;
     
che segue esattamente l'esempio fornito dalla libreria ( :-) ) , con un diverso server , metodo , e diversi argomenti passati alla chiamata , ovvero la DEV_KEY , cioè la chiave sviluppatore generata registrandovi su muovi.roma , e un argomento nullo che a noi non serve ( se popolato è utile per identificare univocamente dispositivi come i cellulari , che sfruttano comunque la propria chiave sviluppatore )

la risposta è una stringa che contiene il token da utilizzare per la chiamata successiva

Adesso è il momento di richiamare il metodo paline.Percorsi , quindi come prima la strutture della classe del client rimane invariata , variando il server , il metodo e gli argomenti della chiamata


string const palineServer("http://muovi.roma.it/ws/xml/paline/7");
string const palineMethod("paline.Percorsi");

xmlrpc_c::clientSimple palineClient;
xmlrpc_c::value paline;

palineClient.call(palineServer, palineMethod, "sss", &paline, str.c_str() , "056", "it");


A questo punto inizia la parte divertente : la risposta salvata nella variabile paline viene restituita come map dalla funzione cvalue() , e quindi creeremo un map con chiavi di tipo stringa , e valori degli elementi xmlrpc_c::value , ovvero il dato arbitrario della libreria , chiamato mymap ( l'altro map uguale , risposta , ci servirà dopo )


map<string, xmlrpc_c::value> mymap , risposta ;


per far diventare la struttura ( la risposta ndr ) in un map , associo la risposta al valore xmlrpc_c::value_struct , e poi tramite il metodo cvalue() la faccio diventare un classico map c++.
A questo punto , posso già isolare l'elemento id_richiesta e mostrarlo sullo schermo

xmlrpc_c::value_struct palineStruct = xmlrpc_c::value_struct(paline);

mymap = palineStruct.cvalue();

cout<< "id_richiesta : " << xmlrpc_c::value_string(mymap["id_richiesta"]).cvalue() << endl;

analogamente ripeto i passaggi precedenti per la struttura risposta
                  
risposta = xmlrpc_c::value_struct(mymap["risposta"]).cvalue();

e mostro i valori dei vari elementi
//I tipi dei vari elementi sono fissati rigidamente seguendo il layout della risposta

map<string, xmlrpc_c::value>::iterator it = risposta.begin();

cout<< it->first << " : " << xmlrpc_c::value_boolean(risposta["abilitata"]).cvalue() << endl;
++it;
cout<< it->first << " : " << xmlrpc_c::value_int(risposta["id_news"]).cvalue() << endl;
++it;
cout<< it->first << " : " << xmlrpc_c::value_int(risposta["monitorata"]).cvalue() << endl;
++it;
cout<< it->first << " : " << endl;


A questo punto arriva l'array dei percorsi. La differenza da una struttura è che questo non avendo delle chiavi per identificare i vari elementi , viene riportato come un vettore. Questo vettore conterrà a sua volta altre strutture contenenti i dati dei vari percorsi.

Riapplicando le stesse operazioni fatte in precedenza si ha :
vector<xmlrpc_c::value> percorsi;

percorsi = xmlrpc_c::value_array(risposta["percorsi"]).cvalue();
		
int numeroPercorsi = percorsi.size();

for( int i = 0; i < numeroPercorsi; i++){

	map<string, xmlrpc_c::value> percorso = xmlrpc_c::value_struct(percorsi[i]).cvalue();
	cout << "	percorso " << i << " : " << endl;
	cout << "		id_percorso: " << xmlrpc_c::value_string(percorso["id_percorso"]).cvalue() << endl;
	cout << "		descrizione: " << xmlrpc_c::value_string(percorso["descrizione"]).cvalue() << endl;
	cout << "		capolinea: " << xmlrpc_c::value_string(percorso["capolinea"]).cvalue() << endl;

}

per compliare l'esempio bisogna eseguire : g++ -o percorsi percorsi.cpp `xmlrpc-c-config c++2 client --libs`

l'esempio è disponibile completamente qui : https://bitbucket.org/Forzaferrarileo/esempi-c-open-api-rsm