I formati JSON ed XML vengono utilizzati per strutturare i dati forniti dalla maggior parte dei web service attualmente esistenti. Pertanto, è abbastanza comune dover elaborare tali formati di file anche in R.
Gli strumenti necessari ci verranno forniti non dal core della piattaforma, bensì da package di cui potremo chiedere l'installazione accedendo al progetto CRAN. Il comando che si occuperà del reperimento di tutto il necessario e della relativa integrazione nel nostro ambiente è install.packages
. Quando lo avvieremo, saremo avvisati che R starà per procedere al download di un package, ci verrà confermata la collocazione in cui esso verrà memorizzato ed un'ulteriore finestra di dialogo ci chiederà di scegliere il server mirror da cui scaricarlo.
Dopo di ciò, ogni volta che vorremo caricare nella nostra sessione di lavoro un package disponibile, sarà sufficiente richiederlo tramite la funzione library
.
Il formato JSON
Quello che segue è un breve estratto di un potenziale contenuto in JSON che vogliamo intepretare tramite R:
{
"corso":"Programmazione Java",
"allievi":[
{
"nome":"Giuliano",
"cognome":"Rossi",
"voti":[8,6,5,7]
},
{
"nome":"Silvio",
"cognome":"Neri",
"voti":[5,3,9,6]
},
{
"nome":"Alessia",
"cognome":"Bianchi",
"voti":[9,9,7,8]
}
]
}
È costituito da un unico oggetto JSON contenente due proprietà: corso che rappresenta il nome di un corso, e allievi costituito da un array di ulteriori oggetti JSON, ognuno dei quali contenente nome, cognome e voti di un allievo.
Per recuperare tali dati in R, dobbiamo innanzitutto arricchire la nostra piattaforma di lavoro della libreria rjson:
install.packages("rjson")
library("rjson")
Come detto, i comandi install.packages
e library
, impartiti da console interattiva, si occuperanno, rispettivamente, di scaricare il pacchetto e di caricarlo nell'ambiente di lavoro. Per completezza, indichiamo entrambi i comandi, anche se dopo aver utilizzato install.packages
una volta, la libreria potrà essere considerata a nostra disposizione; per tale motivo, le sessioni successive di lavoro richiederanno solo una nuova invocazione a library
.
A questo punto potremo inziare la lettura del file: al momento, non chiamiamo in causa l'interazione con la rete, ma supponiamo di avere il file JSON salvato in una collocazione del sistema operativo che, nel nostro caso, sarà D:\voticorso.json.
result <- fromJSON(file = "D:/voticorso.json")
Il comando fromJSON
è tutto ciò che serve per attivare il parsing del file in una struttura dati di R. Assumendo che non ci siano errori di formattazione, l'oggetto result
sarà una lista simile alla seguente:
$corso
[1] "Programmazione Java"
$allievi
$allievi[[1]]
$allievi[[1]]$nome
[1] "Giuliano"
$allievi[[1]]$cognome
[1] "Rossi"
$allievi[[1]]$voti
[1] 8 6 5 7
$allievi[[2]]
$allievi[[2]]$nome
[1] "Silvio"
$allievi[[2]]$cognome
[1] "Neri"
$allievi[[2]]$voti
[1] 5 3 9 6
$allievi[[3]]
$allievi[[3]]$nome
[1] "Alessia"
$allievi[[3]]$cognome
[1] "Bianchi"
$allievi[[3]]$voti
[1] 9 9 7 8
Per estrarre le singole componenti, potremo sfruttare la sintassi utilizzata nelle lezioni precedenti:
result$corso
restituirà una stringa di caratteri contenente il nome del corso, in questo caso "Programmazione Java";result$allievi
fornirà a sua volta una lista di oggetti "allievo".
Esploriamo, a titolo di esempio, il primo allievo:
> result$allievi[[1]]$nome
[1] "Giuliano"
> result$allievi[[1]]$cognome
[1] "Rossi"
> result$allievi[[1]]$voti
[1] 8 6 5 7
> mean(result$allievi[[1]]$voti)
[1] 6.5
Possiamo sfruttare la notazione a doppia parentesi quadra per estrarre valori singoli. Abbiamo così potuto recuperare nome e cognome
dell'allievo registrato alla prima posizione della lista e, successivamente, abbiamo calcolato la media dei suoi voti estrandone la lista.
Per trattare un altro allievo sarà sufficiente indicare una posizione diversa tra doppie parentesi quadre.
Parsing di file XML
Molte fonti su Internet offrono anche dati in formato XML, pertanto sperimenteremo anche questo in R. Scarichiamo un file RSS d'esempio e salviamolo sulla nostra macchina in D:\notiziecinema.xml.
install.packages("XML")
library("XML")
library("methods")
Come nel caso del JSON, il primo comando installerà il package tra le nostre librerie, mentre le invocazioni a library
(entrambe necessarie) lo caricheranno nella sessione di lavoro. Il seguente comando si occuperà del parsing:
result <- xmlParse(file = "D:/notiziecinema.xml")
Provando a vedere il contenuto di result non troveremmo strutture dati di R ma l'output verrebbe offerto come normale testo formattato
in XML. Quello che dobbiamo fare per estrarre i dati è effettuare delle interrogazioni seguendo il percorso dei nodi XML. Ad esempio, in un
file XML una notizia è rappresentata in nodi <item>
al cui interno il sottonodo <title>
ne racchiude il titolo. Potremo avere una lista titoli di notizie in questo modo:
getNodeSet(result, "//item//title")
Ed il seguente sarà uno stralcio dell'output:
[[1]]
<title><![CDATA[ CinemAmbiente, vince Plastic China ]]></title>
[[2]]
<title><![CDATA[ Overdrive, ad agosto kolossal supercar ]]></title>
[[3]]
<title><![CDATA[ Sorrentino, Servillo-Berlusconi e 'Loro' ]]></title>
[[4]]
<title><![CDATA[ Pirateria, nel 2016 danno da 686 mln ]]></title>
Si noti che con il comando getNodeSet(result, "//title")
sarebbe uscita una lista molto simile ma non uguale: avremmo contato infatti un nodo in più consistente nel blocco <title>
non incluso negli <item>
ma corrispondente al titolo dell'intera pagina RSS.
Con i seguenti comandi, approfondiremo l'esplorazione:
> getNodeSet(result, "//item//title")[[2]]
<title><![CDATA[ Overdrive, ad agosto kolossal supercar ]]></title>
> xmlValue(getNodeSet(result, "//item//title")[[2]])
[1] " Overdrive, ad agosto kolossal supercar "
> trimws(xmlValue(getNodeSet(result, "//item//title")[[2]]))
[1] "Overdrive, ad agosto kolossal supercar"
Con l'operatore [[ ]]
potremo estrarre singoli elementi dalla lista mentre con il metodo xmlValue
ne recupereremo solo il testo interno, libero da tag e annotazione CDATA
. Infine, con la comoda funzione trimws
(introdotta in R 3.2) potremo evitare di portare con noi eventuali spaziature in eccesso a inizio e fine della stringa. Esistono anche i metodi xmlName
(che recupera solo il tag del nodo) e xmlAttrs
(che offre la lista di eventuali attributi innestati).