Javascript e XML

Il grande vantaggio introdotto dall'XML trovo consista nell'aver facilitato lo scambio di informazioni. Utilizzare questo formato ha risolto quasi tutti i problemi riguardo lo scambio di dati tra sistemi strutturalmente diversi e che altrimenti avrebbero avuto bisogno di complicate interfacce per comunicare. Non credo di sbagliare sostenendo che se AJAX è il cemento del Web 2.0 sicuramente XML è il mattone di questo nuovo modo di utilizzare e progettare il web. Un documento XML ovviamente, necessita di essere manipolato (spesso trasformato) affinchè le informazioni riportate al suo interno possano essere fruite. In questo articolo vedremo quindi come un file XML possa essere letto con Javascript , le differenze del DOM nella manipolazione tra HTML e XML e infine, come applicare un foglio XSLT ad un XML usando sempre Javascript. Leggere un file XML: un metodo alternativo a XMLHTTPRequest È noto, e direi piuttosto scontato, che leggere un file XML in remoto con Javascript può essere possibile usando XMLHTTPRequest. Non molti sanno però che all'oggetto su cui si fonda AJAX si affianca una valida alternativa che permette anch'essa di leggere file XML (e solo file di questo tipo). Al solito il metodo viene invocato nei due browser piu diffusi, Internet Explorer e Firefox, in maniera differente ma a fronte di alcuni svantaggi, si dimostra essere maggiormente adatto alla manipolazione di documenti XML. Vediamo allora come inizializzare i nostri oggetti e commentiamo insieme il codice che segue: if (document.implementation && document.implementation.createDocument) { xmlDoc = document.implementation.createDocument("", "", null); xmlDoc.onload = readXML(); } else (window.ActiveXObject) { xmlDoc = new ActiveXObject("MSXML2.DOMDocument"); xmlDoc.onreadystatechange = function () { if (xmlDoc.readyState == 4) readXML() }; } xmlDoc.load("fileXMLdacaricare"); Per Firefox, questo metodo alternativo si invoca usando document.implementation mentre per Explorer occorre creare una instanza ActiveX dell'oggetto MSXML2.DOMDocument. I metodi sono entrambi asincroni per default (ma possono essere resi sincroni ponendo la proprietà async a false): xmlDoc.async = false e mentre per document.implementation esiste una funzione onload che ci dice quando il documento XML è stato creato, per MSXML occorre fare un controllo sulla proprietà readyState i cui valori possono variare da 1 a 4: quando readyState è pari a 4 appunto, significa che il file XML è stato completamente caricato (un po come con XMLHTTPRequest). In particolare nella nostra funzione, controlliamo che il documento sia stato caricato e poi facciamo partire la funzione readXML() che nel nostro esempio ci servirà per studiare i vari metodi messi a disposizione per manipolare i dati del file XML. Torniamo brevemente al metodo usato con Firefox: come si vede dal codice, la funzione document.implementation.createDocument ha tre argomenti che nel nostro caso sono vuoti. In ordine essi sono: namespace, il tag root del documento e null perché le funzioni associate a questo parametro non sono state ancora implementate. Usandoli possiamo creare anche documenti XML vuoti che potremmo riempire con le API del DOM. Analogamente, ma in modo più macchinoso, anche Internet Explorer mette a disposizione le funzioni per creare documenti XML vuoti. A cosa può servire questo? Ad esempio a creare un output XML per una base di dati sui cui dati potremo lavorare manipolando poi l'XML salvato in locale, senza gravare ulteriormente sul nostro server. Ritorniamo a parlare delle differenze tra XMLHTTPRequest e il metodo alternativo che stiamo usando. XMLHTTPRequest può essere usato per qualsiasi tipo di documento di testo (non solo XML quindi) mentre il metodo alternativo funziona solamente con file XML. XMLHTTPRequest funziona solo con il protocollo HTTP e quindi qualsiasi altro protocollo non è utilizzabile per accedere ai file. Come avete intuito, il metodo alternativo non è invece legato a nessun protocollo in particolare e quindi può caricare anche file XML che si trovano sul file system del vostro server (oppure su un server ftp). Infine, quando usiamo il metodo alternativo, con HTTP possono essere generate solamente richieste di tipo GET e non di tipo POST.

1

Come lo leggo? Una volta compreso che la lettura del file XML può essere effettuata in due modi, passiamo a vedere come con il DOM sia possibile usare le informazioni contenute nel nostro file XML. La funzione che segue legge un qualsiasi file XML e ne mostra il nome del tag e il suo contenuto: function readXML(app) { var x = xmlDoc.getElementsByTagName('item'); var text = ''; for (i=0;i < x.length;i++) { for (j=0;j < x[i].childNodes.length;j++) { if (x[i].childNodes[j].nodeType != 1) continue; //text += x[i].childNodes[j].nodeName + ": " + x[i].childNodes[j].firstChild.nodeValue + ""; text += x[i].childNodes[j].nodeName + ": " + x[i].childNodes[j].firstChild.nodeValue + ""; } } alert(text); var app = document.getElementById('textAPP'); app.innerHTML = text; }

Analizziamo brevemente il codice: accedere ad un nodo dell'XML si riduce a navigare i suoi rami fino a raggiungere l'elemento desiderato. Nel nostro caso (ripeto, un RSS) vogliamo visualizzare tutti gli elementi figli di tutti gli elementi item. Quindi instanziamo un array di elementi item (var x = xmlDoc.getElementsByTagName('item')) dopodiché iteriamo su quest'array e per ogni figlio dell'elemento (x[i].ChildNodes[j]). L'esempio mostra le due caratteristiche principali di childNodes: NodeName, che ci permette di ottenere il nome del tag e firstChild.nodeValue, che invece restituisce il valore eventualmente contenuto tra i tag. Come avrete notato c'è una riga che non è stata commentata: if(x[i].childNodes[j].nodeType != 1). In realtà si tratta di un hack per Firefox. Il browser della Mozilla Foundation infatti, interpreta come firstChild il nodo tra item e description che, in questo caso però, non ha nessuno value da mostrare. Ciò causa un errore che blocca l'esecuzione dello script. È buona norma quindi (una volta individuato il nodo padre) inserire questo piccolo hack. HTML e XML: le differenze nel DOM (e non solo...) Abbiamo appena visto che per accedere i valori di un file XML usiamo un approccio che ricorda molto da vicino il DOM ben noto per le varie applicazioni Javascript tipiche del Web 2.0 (e non solo). In effetti quando il W3C progettò le API per DOM, l'idea era quella di renderle valide per ogni linguaggio compreso chiaramente XML: anzi, diciamo pure che XML ha inspirato la progettazione delle API tant'è che HTML viene gestito dal DOM grazie ad una estensione delle API originali. Ma qual è la differenza fondamentale tra il DOM usato per l'XML e quello usato per HTML? Facile: l'utilizzo della funzione getElementById. Infatti mentre in HTML questo è il metodo per accedere ad un elemento della pagina (ovviamente se identificato da un id univoco) in XML è probabile che il valore restituito usando questa funzione, sarà null. Questo perché in XML non è sufficiente dichiarare un attributo id in un tag e accedere poi a quel tag con getElementById: occorre anche "tipizzare" l'attributo, e per farlo va definito il DTD per il documento XML e poi dichiararlo nel DOCTYPE. Un'altra differenza tra HTML e XML è che HTML ha una proprietà body che si riferisce al tag <body> mentre per XML solo la proprietà documentElement si riferisce al tag root del documento. Infine, per accedere al valore di un attributo di un tag in XML va utilizzato getAttribute(nomeAttributo) mentre per modificarlo si usa setAttribute(nomeAttributo). Quindi: se abbiamo il tag: <esempioTag attr="ciao"> e vogliamo accedere al valore dell'attributo attr, si scrive: getAttribute(attr). Ovviamente questa operazione non è permessa con documenti HTML.

2

Javascript, XML e XSLT La naturale estensione di XML per la trasformazione di un documento XML in formati fruibili all'utente finale è senz'altro XSL. In Javascript è possibile applicare un file XSL ad un file XML sia in Internet Explorer che in Firefox, con la solita discrepenza sui metodi di base e sulle modalità di inizializzazione. Occorre però precisare in questo caso, che il W3C non ha ancora definito nessuna API standard per le trasformazioni XSL con il DOM o con XML per Javascript e quindi per una volta, giustifichiamo scelte diverse a fronte di una poco matura situazione ad "alti livelli". Passiamo al concreto e partiamo con Firefox le cui API proprietarie per la trasformazione di documenti XML con XSL viene garantita dall'oggetto XSLTProcessor. In Internet Explorer invece l'oggetto predisposto è TransformNode(). Vediamo nel seguente esempio come creare una funzione cross browser per applicare un file XSL (che supponiamo di avere in remoto, cioè un URL) ad uno specifico nodo del nostro file XML (supponiamo di aver già riconosciuto quale browser stiamo utilizzando e riusiamo la funzione per caricare file XML che abbiamo visto in precedenza, ovvero l'oggetto ottenuto, XMLDoc che chiamiamo XSLDoc quando carichiamo il file XSL): XSLDoc.load(URLdelFileXSL); if (typeof XSLTProcessor != "undefined") { //stiamo usando Firefox var xsltProcessor = new XSLTProcessor(); xsltProcessor.importStylesheet(XSLDoc); var app = xsltProcessor.transformToFragment(nodoDelDOMDaTrasformare); } else { //stiamo usando Internet Explorer //quindi il nodo che vogliamo trasformare ha la funzione transformNode tra i suoi metodi var app = nodoDelDOMDaTrasformare.TransformNode(XSLDoc) } In Firefox è possibile usare anche un altro metodo al posto di transformToFragment (che come TransformNode per IE, restituisce un nodo) ed è transformToDocument: l'oggetto che se ne ricava è un document HTML se l'XSL produce come output un HTML oppure un documento XML se l'XSL produce un file XML. Javascript e XPath Chiudiamo con un accenno alle espressioni XPath e le relative API del W3C per la selezione dei nodi nel DOM usando questo approccio. Al solito anche qui, Firefox ha implementato le API usando il metodo evaluate() del document object, che compila una espressione XPath in modo che sia possibile valutarla diverse volte in modo efficiente. Internet Explorer invece, fornisce i due metodi selectSingleNode() e selectNodes() esclusivamente per documenti XML (e quindi non funzionano con documenti HTML!). XPath è ovviamente una parte che richiederebbe una serie di articoli per essere analizzata a fondo e per questo mi fermo qui, limitandomi all'introduzione degli strumenti che dovete usare se volete cercare nodi all'interno dei vostri documenti, usando appunto Javascript. Considerazioni Finali Abbiamo visto quindi come Javascript si sia ormai evoluto, in un linguaggio che permette sofisticate operazioni un tempo appannaggio esclusivamente dei linguaggi server side. Come già detto, molte di queste innovazioni hanno fatto si che nascesse il Web come lo conosciamo oggi, e ovviamente XML è una parte fondamentale per l'evoluzione (anche) futura della user experience durante la navigazione e la fruizione dei contenuto sul web. Javascript copre completamente ogni aspetto necessario a maneggiare le informazioni in questo formato e in questo articolo ho cercato di toccare un po' tutti gli aspetti. Come avrete notato inoltre, i browser che ho citato sono stati solamente Internet Explorer e Firefox: questo perché il resto dei browser non ha ancora un supporto Javascript ad XSLT né tanto meno ad XPath: in questi casi viene consigliato l'utilizzo di AJAXSLT una libreria sviluppata da Google. Questo è tutto. Alla prossima e buon divertimento!

3