Action script e interazione con XML

In questa lezione tratteremo i seguenti argomenti:

1. caricare in un filmato dati formattati in XML edeseguirne il parsing;
2. costruire un semplice preloader per informarel’utente sullo stato del download;
3. inviare da Flash dati formattati in XML.


::1.

XML (eXtensible Markup Language) è il piùdiffuso standard per la formattazione e la strutturazione deidati, e consente a programmi diversi di comunicare tra diloro.
Anche Flash “parla” questo linguaggio, nel sensoche può importare dati formattati in XML ma puòanche creare dati XML da inviare ad applicazioni server.
Il vantaggio di saper comunicare in XML da parte di Flashsta nel fatto che è possibile importare dati complessi(per esempio un oggetto con delle proprietà), moltopiù potente della semplice importazione di variabilicol rispettivo valore.
La sintassi di XML non si discosta molto da quelladell’HTML con l’uso di tag (o nodi in XML).

Esamiamo una semplice struttura XML creata con un editor ditesti (il file è stato salvato con codificaUnicode):

Codice:

<?xml version="1.0"?><AMMINISTRAZIONE><DIPENDENTE id="0054D">   <NOME>aaa</NOME>   <INDIRIZZO>bbb</INDIRIZZO>   <MANSIONE>Addetto alla contabilità</MANSIONE></DIPENDENTE><DIPENDENTE id="0054E">   <NOME>ccc</NOME>   <INDIRIZZO>ddd</INDIRIZZO>   <MANSIONE>Addetto paghe e contributi</MANSIONE></DIPENDENTE><DIPENDENTE id="0054F">   <NOME>eee</NOME>   <INDIRIZZO>fff</INDIRIZZO>   <MANSIONE>Addetto rapporti col personale</MANSIONE></DIPENDENTE></AMMINISTRAZIONE>



La prima riga è una dichiarazione iniziale in cuiabbiamo incluso solo la proprietà‘version’, ma ne esistono delle altre, in tutti imodi questà è la dichiarazione minima.
I tag come <AMMINISTRAZIONE> e <DIPENDENTE>hanno nomi personalizzati (un vantaggio dell’XMLrispetto all’HTML in cui i tag hanno nomi predefiniti)e servono ad assegnare nomi ai dati racchiusi in essi.
Guardando la struttura possiamo dire che il primo ed unicofiglio della struttura è il nodo<AMMINISTRAZIONE>, il quale ha tre nodi figli<DIPENDENTE>.
A loro volta ciascun nodo <DIPENDENTE> ha tre nodifigli, <NOME>, <INDIRIZZO> e <MANSIONE> iquali hanno i rispettivi valori.
Ogni nodo <DIPENDENTE> ha anche al suo interno unattributo paragonato ad una proprietàdenominata di un oggetto.
E’ possibile aggiungere quanti attributi si vuole, illoro uso è adatto quando si sa, per esempio, che ognidipendente ha un numero identificativo.

Come si è potuto notare abbiamo creato la strutturainserendo spazi e ritorni a capo per facilitare lacomprensione, ma può sorgere un problema quando Flashimporta la struttura.
Infatti anche quando il codice XML è scrittocorrettamente se si osserva il filmato con un player la cuiversione è precedente alla 5.41, gli spazi bianchivengono interpretati come nodi dando risultati inaspettati infase di parsing, per questo viene utilizzata laproprietà ignoreWhite che risolve il problemadelle versioni più vecchie.

Passiamo ora a vedere come Flash importa e parserizza unastruttura di dati in XML.

my_xml = new XML ();my_xml.ignoreWhite = true;my_xml.onLoad = parsingXML;my_xml.load ("dipendenti.xml");


Lo script crea un’istanza della classe XML e laassegna alla variabile my_xml.
La seconda riga imposta la proprietà ignorWhite, dicui si è parlato prima, a true, quindi la terza rigaassegna all’evento onLoad dell’oggetto XML ilriferimento alla funzione di callback parsingXML() (siricordi che in questo caso non vanno inserite le parentesidopo il nome della funzione perché non è unachiamata ma bensì l’assegnazione ad un evento diun riferimento alla funzione).
L’evento onLoad viene innescato al completamento delcaricamento ma anche se il caricamento non è avvenutocon successo (lo vedremo tra poco), in ogni caso solo inquesto momento viene eseguita la funzione di callback.
Infine il metodo load viene invocato per iniziare ildownload.

Si noti che al posto delnome del file con estensione .xml ci sarebbe potuto essereanche l’indirizzo di un file asp per esempio, cheperò deve restituire dati in XML.

Comunque se i dati che Flash deve ricevere sono formattatiin questo modo bisogna preparare il “contentore”giusto e quindi istanziare la classe XML.
Una volta caricati i dati nell’oggetto XML, sipuò cominciare il proceso di parserizzazione,cioè di estrazione dei dati dalla struttura XMLimportata.

function parsingXML (success) {if (!success) {trace ("caricamento fallito");return;}//parsing}

Questa funzione viene richiamata al termine del caricamento,che esso sia andato a buon fine o che sia fallito.
Per questo la funzione riceve un parametro che se ètrue (il caricamento è stato completato con successo)va avanti altrimenti, richiamando return, esce.
Il parametro è una funzionalitàdell’evento onLoad e viene inviato automaticamente allafunzione, il nome è puamente arbitrario.

Facciamo degli esempi utilizzando alcune delleproprietà più comuni, all’interno dellafunzione di callback, per questo utilizzando l’aliasanonimo this faremo riferimento all’oggetto al qualeè associato l’evento, ovvero l’oggettomy_xml.

childNodes restituisce un array formato dai nodifigli in un punto della struttura.
Quindi per esempio myArray = this.childNodes assegnaalla variabile myArray una matrice con i nodi figli deldocumento XML, in questo caso<AMMINISTRAZIONE>[…]</AMMINISTRAZIONE>ovvero il nodo root.

Scrivendo invecetrace(this.childNodes[0].childNodes[0]) avremo ilprimo nodo figlio del primo nodo figlio del documento XMLcioè

Codice:

<DIPENDENTE id="0054D">   <NOME>aaa</NOME>   <INDIRIZZO>bbb</INDIRIZZO>   <MANSIONE>Addetto alla contabilità</MANSIONE></DIPENDENTE>


Da notare l’accesso ai nodi (childNodes[0]), proprioperché childNodes restituisce un array.

Invecetrace(this.childNodes[0].childNodes[0].childNodes[0])sarà uguale a <NOME>aaa</NOME>.

Volendo estrarre il nome ed il valore del nodoscriveremo:

trace(this.childNodes[0].childNodes[0].childNodes[0].nodeName)avremo “NOME”,

trace(this.childNodes[0].childNodes[0].childNodes[0].firstChild.nodeValue)avremo aaa.

In quest’ultimo caso per ottenere il valore del nodonon è sufficiente scriverethis.childNodes[0].childNodes[0].childNodes[0].nodeValue maoccorre specificare la proprietà firstChild.

In poche parole il testo che appare all’interno delnodo è il valore del primo nodo figlio del nodocorrente.

Scrivendo per esempiotrace(this.childNodes[0].childNodes[0].firstChild.nodeValue)avremo come risultato ‘null’ perché ilnodo <DIPENDENTE> non ha nessun valoreall’interno di esso come invece i nodi <NOME>,<INDIRIZZO> e <MANSIONE>.
Infattithis.childNodes[0].childNodes[0].childNodes[2].firstChild.nodeValueè uguale a: Addetto alla contabilità.

Ancora, la proprietà attributes restituisce un arrayassociativo composto da tutti gli attributi del nodocorrente.
Scrivendo trace(this.childNodes[0].childNodes[0].attributes.id)otterremo l’identificativo del primo dipendente,scrivendo invece trace(this.childNodes[0].childNodes[1].attributes.id)quello del secondo dipendente.
Questa riga può essere letta in questo modo: “il valore dellaproprietà id dell’oggetto generico attributesdel secondo nodo figlio del primo nodo figlio della strutturaXML”.

Facciamo un ulteriore esempio per capire meglio i concettiappena discussi, provando ad inserire i dati importati in unacasella di testo identificata come box_txt.
Il procedimento consiste nel trasferire i dati dallastruttura XML in un array composto da tanti oggetti genericiquanti sono i dipendenti.
Ogni oggetto generico contiene una proprietàdenominata corrispondente all’attributo“id” e tante proprietà denominate quantisono i nodi figli di ogni nodo <DIPENDENTE>.
Tutto questo viene svolto attraverso due cicli forsemplici.
 

function parsingXML (success) {if (!success) {trace ("problema");return;}dipendenti = new Array ();for (t = 0; t < this.childNodes[0].childNodes.length; t++) {var objDipendenti = new Object ();objDipendenti.id_ = this.childNodes[0].childNodes[t].attributes.id;for (j = 0; j < this.childNodes[0].childNodes[t].childNodes.length; j++) {objDipendenti[this.childNodes[0].childNodes[t].childNodes[j].nodeName] = this.childNodes[0].childNodes[t].childNodes[j].firstChild.nodeValue;}dipendenti[t] = objDipendenti;}view ();}



Se il caricamento è avvenuto con successo allora sipuò procedere, creando prima un array (dipendenti)destinato a contenere ogni dipendente sotto forma di oggettogenerico.
Quindi per ogni dipendente for (t = 0; t <this.childNodes[0].childNodes.length; t++), istanziandola classe Object, si crea appunto un oggetto genericotempoaneo che conterrà il valore dell’attributoe i valori dei nodi figli (NOME, INDIRIZZO, MANSIONE).
Per prima cosa però si crea una proprietà id_alla quale viene assegnato il valore dell’attributo“id”.

Il secondo ciclo for (con l’iterante j) potrebbesembrare più complesso, ma in realtà non loè.
In pratica per ogni nodo figlio del dipendente correntefor (j = 0; j <this.childNodes[0].childNodes[t].childNodes.length; j++),ne vengono estratti i valori ed assegnati alle rispettiveproprietà denominate il cui nome viene ricavato dalnome dei nodi (NOME, INDIRIZZO, MANSIONE).

Si noti che sono state usate le parentesi quadre ad indicareil fatto che il valore restutuito dathis.childNodes[0].childNodes[t].childNodes[j].nodeNameè una stringa e pertanto, essendo il nome di unaproprietà, deve essere prima convertito.
Alla fine viene richiamata la funzione view() pervisualizzare i risultati.
 

function view () {var string = "<b><font size= "12">:: Dipartimento " + my_xml.childNodes[0].nodeName + "</font></b>" + newline + newline + ":: Elenco dipendenti" + newline + newline;for (var t = 0; t < dipendenti.length; t++) {var id = ".: Identificativo: <b>" + dipendenti[t].id_ + "</b>" + newline;var nome = ".: Nome: <b>" + dipendenti[t].NOME + "</b>" + newline;var indirizzo = ".: Indirizzo: <b>" + dipendenti[t].INDIRIZZO + "</b>" + newline;var mansione = ".: Mansione: <b>" + dipendenti[t].MANSIONE + "</b>" + newline + newline;string += id + nome + indirizzo + mansione;}box_txt.htmlText = string;}



Nota: In questa funzionesi è potuto accedere direttamente ai valori delleproprietà perché ogni oggetto contiene lostesso numero di proprietà, in caso contrario sisarebbe dovuto accedere con un ciclo.

L’operazione di spostare i dati nell’array enegli oggetti generici è stata fatta solo per unaquestione di comodità e per un più facileaccesso ai dati stessi, avremmo potuto visualizzare i daticon un unico blocco di codice.
 

function parsingXML (success) {if (!success) {trace ("problema");return;}var string = "<b><font size= "12">:: Dipartimento " + this.childNodes[0].nodeName + "</font></b>" + newline + newline + ":: Elenco dipendenti" + newline;for (var t = 0; t < this.childNodes[0].childNodes.length; t++) {string += newline + ".: Identificativo: <b>" + this.childNodes[0].childNodes[t].attributes.id + "</b>" + newline;for (var j = 0; j < this.childNodes[0].childNodes[t].childNodes.length; j++) {string += ".: " + this.childNodes[0].childNodes[t].childNodes[j].nodeName + ": <b>" + this.childNodes[0].childNodes[t].childNodes[j].firstChild.nodeValue + "</b>" + newline;}}box_txt.htmlText = string;}



::2.

Il caricamento di informazioni testuali in Flash avvieneabbastanza rapidamente ma può essere comodo a volte,se il file xml è abbastanza pesante, tenerecostantemente informato il visitatore dello stato deldownload.
La creazione di un preloader è abbastanza semplice,la classe XML infatti fornisce due metodigetBytesLoaded() e getBytesTotal() alloscopo.

Per rivedere all’opera il preloaded èsufficiente eliminare il contenuto in linea (in Explorer: Strumenti > OpzioniInternet > Elimina File > spuntare la voce Eliminatutto il contenuto in linea > OK > OK >Aggiorna).

Di seguito viene riportato il codice del primo frame delprogetto allegato.

stop ();my_xml = new XML ();my_xml.ignoreWhite = true;my_xml.onLoad = parse;my_xml.load ("mytest.xml");//function loading () {if (my_xml.getBytesLoaded () == 0) {return;}var loaded = my_xml.getBytesLoaded ();var total = my_xml.getBytesTotal ();var percent = Math.floor ((loaded / total) * 100);box_txt.htmlText = "<b><font color = "#FF0000"> :: </font></b> Total Kb XML Data " + Math.floor (total / 1024) + "<b><font color = "#FF0000"> :: </font></b> Progress download " + Math.floor (loaded / 1024) + "<b><font color = "#FF0000"> :: </font></b>" + percent + "% <b><font color = "#FF0000"> :: </font></b>";}//intervalID = setInterval (loading, 50);//function parse (success) {clearInterval (intervalID);if (success) {nextFrame ();}}


Innanzitutto viene istanziata la classe XML e definita lafunzione da invocare al completamento del download(parse()).
Quindi viene indicata a Flash la fonte da cui caricare idati attraverso il metodo load().
Ricordo che il file può anche essere un file .asp cheperò deve restituire i dati in formato XML.
In questo esempio è stato utilizzatosetInterval(funzione, intervallo in millisecondi), ilquale consente di richiamare e quindi eseguire una funzionead intervalli di tempo prestabiliti.
setInterval è stato associato alla variabileintervalID in modo da poterlo richiamare per esserecancellato al termine del caricamento con l’azioneclearInterval(intervallo) nella funzione parse().
Nel nostro caso la funzione che controlla il download(loading()) viene richiamata ogni 50 millisecondi.

Nella funzione loading() si trova una parte importante delloscript.
L’istruzione if è una semplice via di fuga perevitare di dover eseguire calcoli con lo 0, che consente diuscire dalla funzione (return è stato trattato neltutorial sulle funzioni) se my_xml.getBytesLoaded () èuguale a 0.
Le righe successive sono abbastanza intuitive, calcolano lapercentuale di download, dividendo i bytes caricati perquelli totali, e costruiscono una stringa per visualizzare ilrisultato in Kbyte (dividendo per 1024).
Da notare l’uso del carattere di escape ‘’per indicare a Flash che le virgolette doppie devono essereconsiderate come parti integranti all’interno dellastringa e non come delimitatori della stringa.
Al termine del caricamento, comunque vada si interrompe lachiamata continua alla funzione loading, e se èavvenuto con successo si passa al frame successivo.

Nota: per potervisualizzare correttamente il preloader, è necessariotrasferire i file tranne il .fla su un server, altrimenti ilcaricamento in locale sarebbe così veloce da nonconsentire la visualizzazione delle informazioni durante ildownload.

::3.

L’oggetto XML permette anche di inviare dati nelformato XML ad un URL specifco.
Il processo non è difficile, è sufficientecome al solito istanziare la classe XML e passareall’istanza una stringa contenente i dati strutturatiin XML.
Quindi utilizzando i metodi send(),sendAndLoad() o load() è possibileuploadare i dati.

Supponiamo di dover creare una struttura XML e di doverlainviare ad uno script lato server.
Il codice sarà il seguente:

stringaXML = "<AMMINISTRAZIONE><DIPENDENTE id="0054D"><NOME>aaa</NOME><INDIRIZZO>bbb</INDIRIZZO><MANSIONE>Addetto alla contabilità</MANSIONE></DIPENDENTE></AMMINISTRAZIONE>";URLServerSide = "http://www.sitod_esempio.it/scriptServerSide.asp";xmlObject_xml = new XML (stringaXML);xmlObject_xml.send (URLServerSide);


Da notare alcune cose: innanzitutto il parametro passatoall’istanza dell’oggetto XML, ovvero la stringacontenente la struttura XML.
Quindi l’invocazione del metodo send ed il rispettivoparamentro, l’indirizzo dello script server side.
Il procedimento può riassumersi così: Flash memorizza in una stringa lastruttura XML quindi questa viene passata all’oggettoxml xmlObject_xml il quale viene inviato al file.asp.
Se Flash avesse dovuto anche ricevere dei dati dal fileremoto avremmo potuto invocare il metodo load() oppuresendAndLoad creando per quest’ultimo un oggettopreposto a caricare i dati di ritorno.