Javascript, HTML, CSS e... !
0 commenti

Lavorare con l'XML ed i web services

Inviare una richiesta HTTP POST con XML in input e output e parsing della risposta

Esistono web services che, sia per l'autenticazione che per il recupero delle informazioni, per essere interrogati richiedono una chiamata in POST al servizio che sia corredata di un parametro in input sotto forma di struttura XML.
Il codice di esempio in questo tutorial mostra come può essere effettuata una chiamata in post di questo tipo e successivamente come può essere effettuato il parsing della risposta, anch'essa in formato XML, per recuperarne le informazioni desiderate.

Poniamo l'esempio di dover interrogare un servizio web, messo a disposizione delle terze parti da una compagnia di trasporti locale, per la consultazione degli itinerari, degli orari, delle disponibilità, ecc... e che ci interessi la chiamata per il recupero della lista delle tratte coperte dal servizio per renderle disponibili all'utente nel nostro ipotetico applicativo.
La compagnia di trasporti locale ci fornirà pertanto le credenziali di autenticazione ai web services (ad esempio, 'username': 12345 e 'password': 67890) e la documentazione per la definizione degli URL ai quali inviare la chiamata in POST e dei parametri XML che ciascun servizio si aspetta di ricevere in input.
Con queste informazioni creiamo la nostra chiamata in POST con XML con Google Apps Script:

// XML input per il recupero tratte
var ws_url = 'http://ws.test.it/wsGetRoutes.asmx/GetRoutesXML';
var ws_xml = '<?xml version="1.0" encoding="utf-16"?><GetRoutesRQ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" LangID="IT"><POS><Source UserName="12345" PassWOrd=67890" ></Source></POS></GetRoutesRQ>';

// Chiamata HTTP POST
function getXMLResult(ws_url, ws_xml) {
  var url = ws_url;
  var options = {
    "method": "post",
    "headers": {
      "content-type": "application/x-www-form-urlencoded",
      "cache-control": "no-cache"
    },
    "payload" : "XML=" + ws_xml
  };
  return UrlFetchApp.fetch(url, options).getContentText();
}

function getRoutes() {
  var response = getXMLResult(ws_url, ws_xml);
  
  // operazioni di parsing dell'output...
  // ...
}

La struttura XML utilizzata in input è stata semplificata per lo scopo illustrativo del tutorial ma può raggiungere diversi livelli di complessità a più nodi.
La parte che distingue questa richiesta da una classica richiesta HTTP POST è proprio la presenza del parametro payload e del relativo valore che inizia con "XML=" seguito dalla struttura XML da inviare.
Da notare anche l'utilizzo di getContentText() applicato all'output che permette di restituire il contenuto di una risposta HTTP codificata come una stringa, in modo da predisporla alla successiva gestione ed elaborazione.

Una volta effettuata l'interrogazione al web service, nella variabile response sarà presente la risposta desiderata con la lista delle tratte percorse dalla compagnia di trasposti locale, in formato XML (al di là del caso del nostro esempio, tengo a precisare che nonostante la chiamata possa contenere un parametro XML in input non significa che anche la risposta sia fornita necessariamente in formato XML, dipende da come è stato costruito il servizio).

Supponiamo pertanto che la risposta, in formato XML, abbia una struttura simile alla seguente:

<?xml version="1.0" encoding="utf-8"?>
<GetRoutesRS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Success>True</Success>
  <Routes>
    <IG_Route>
      <Departure LocationCode="LI" LocationDescription="LIVORNO" ></Departure>
      <Arrival LocationCode="PI" LocationDescription="PISA" ></Arrival>
    </IG_Route>
    <IG_Route>
      <Departure LocationCode="LI" LocationDescription="LIVORNO" ></Departure>
      <Arrival LocationCode="LU" LocationDescription="LUCCA" ></Arrival>
    </IG_Route>
    <IG_Route>
      <Departure LocationCode="LI" LocationDescription="LIVORNO" ></Departure>
      <Arrival LocationCode="FI" LocationDescription="FIRENZE" ></Arrival>
    </IG_Route>
    <IG_Route>
      <Departure LocationCode="PI" LocationDescription="PISA" ></Departure>
      <Arrival LocationCode="LI" LocationDescription="LIVORNO" ></Arrival>
    </IG_Route>
    <IG_Route>
      <Departure LocationCode="LU" LocationDescription="LUCCA" ></Departure>
      <Arrival LocationCode="LI" LocationDescription="LIVORNO" ></Arrival>
    </IG_Route>
    <IG_Route>
      <Departure LocationCode="FI" LocationDescription="FIRENZE" ></Departure>
      <Arrival LocationCode="LI" LocationDescription="LIVORNO" ></Arrival>
    </IG_Route>
  </Routes>
</GetRoutesRS>

Per recuperare le singole tratte in modo da poterle gestire ed utilizzare in un nostro ipotetico applicativo è opportuno effettuare alcune operazioni di parsing tramite il servizio XmlService di Google Apps Script che permette di analizzare e navigare (ma anche creare) documenti XML.
Di seguito la porzione di codice che permette di recuperare le informazioni dall'XML di esempio:

function getRoutes() {
  var response = getXMLResult(ws_url, ws_xml); // funzione mostrata nel codice precedente
  parsingXML(response);
}

function parsingXML(xml_result) {

  var result_parsed = XmlService.parse(xml_result);
  var root = result_parsed.getRootElement();
  
  var routes, routes_length, route, route_length, route_children, route_children_name;
  var departure_code, departure_description, arrival_code, arrival_description;
  
  var success = root.getChildren()[0].getText();
  if (success) {
    routes = root.getChildren()[1];
    routes_length = routes.getChildren().length;
    
    for(var i=0; i<routes_length;i++) {
      route = routes.getChildren()[i];
      route_length = route.getChildren().length;
      
      for (var j=0; j<route_length;j++) {
        route_children = route.getChildren()[j];
        route_children_name = route_children.getName();
        
        if (route_children_name == 'Departure') {
          departure_code = route_children.getAttribute('LocationCode').getValue();
          departure_description = route_children.getAttribute('LocationDescription').getValue();
        }
        if (route_children_name == 'Arrival') {
          arrival_code = route_children.getAttribute('LocationCode').getValue();
          arrival_description = route_children.getAttribute('LocationDescription').getValue();
        }
      }
      
      Logger.log(departure_description + ' - ' + arrival_description + ' (' + departure_code + '-' + arrival_code + ')');
      
    }
  } 
}

I metodi utilizzati sono pressoché autoesplicativi, con getRootElement() si accede al primo nodo del file XML, con i getChildren()[idx] si accede all'elemento figlio in posizione idx rispetto al nodo precedente (lo 0 è la prima posizione), con getName() si recupera il nome del tag del nodo, con getText() quello del contenuto all'interno dei tag del nodo mentre con getAttribute('nomeAttributo').getValue() si recupera il valore dell'attributo indicato (nel caso 'nomeAttributo' è rappresentato da 'LocationCode' o 'LocationDescription') del nodo per il quale è richiesto (nell'esempio 'Departure' o 'Arrival').
Di seguito la lista dei percorsi estratti dall'output XML visualizzata nel file di log:



Log del parsing XML con la lista delle tratte

Fig. 1 - Lista dei percorsi estratti dall'XML e mostrati nel file di log


Qualora ne aveste bisogno, potete fare riferimento alla documentazione ufficiale per la consultazione degli altri metodi delle classi del servizio XmlService.

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

scrivi un commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web