JavascriptProva

domenica 28 ottobre 2012

Oggetto con proprietà dai nomi uguali a quelli dei nodi dell'XML

Procediamo per ordine.
Bisogna innanzitutto vedere quali sono i primi nodi di un documento.
Prendiamo il mio documento xml piuttosto semplice e vediamo quali sono i primi nodi.
La prima proprietà di un oggetto che rappresenta un record del mio database dovrebbe essere il tag che rappresenta.
Cerco di creare una proprietà dell'oggetto che abbia lo stesso nome del tag che rappresenta.
Come fare?

La proprietà la chiamo tipo in quanto il suo nome è rappresentativo del tipo di informazione contenuto nel record. Dato che la mia tabella è fatta di persone, il tag si chiama <persona>.
Ecco il codice:
function record(){
 this.tipo=root.childNodes[0] 
}
In pratica assegno alla proprietà tipo il primo elemento figlio del documento.
Questo approccio non è corretto. Infatti se poi vado a usare istanze dell'oggetto che rappresentano records diversi dal primo, le loro proprietà tipo non dovranno rappresentare il primo nodo figlio del documento, ma quelli successivi.

Il ragionamento che posso fare è questo:
  • individuare il nome dei primi nodi figli del documento.
  • assegnare alla proprietà tipo del record il nodo figlio con quel nome identificato da un numero.
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this.tipo=root.getElementsByTagName(nomeNodo)[num];
}
La prima riga prende il nome del primo nodo figlio del documento.
La seconda riga assegna alla proprietà tipo dell'oggetto il nodo figlio identificato dal numero num, presente come parametro.
Ma ora voglio di più.
Voglio che il nome della proprietà sia uguale al nome del primo nodo figlio che viene trovato.
Ci provo:
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this[nomeNodo]=root.getElementsByTagName(nomeNodo)[num];
}
e poi istanzio l'oggetto chiedendo di mostrarmi il nome del nodo della proprietà persona dell'oggetto.
function init(){
 Record=new record(0);
 alert(Record.persona.nodeName);
}
Dunque la proprietà persona dell'oggetto richiama immediatamente l'omonimo tag di ogni record della tabella.
Sembra che stia procedendo bene, almeno questo è quanto sono riuscito a fare finora.

Ora andiamo avanti con altre proprietà...
Ecco, sembra che sia riuscito a ottenere un codice con un minimo di funzionalità:
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this[nomeNodo]=root.getElementsByTagName(nomeNodo)[num];
 
 var nodo=this[nomeNodo];
 
 for(var i=0;i<nodo.childNodes.length;i++){
  nomeNodo=nodo.childNodes[i].nodeName;
  this[nomeNodo]=nodo.getElementsByTagName(nomeNodo);
 }
}
La prima parte desume il nome dei primi nodi figli nella variabile nomeNodo, quindi la usa per creare una proprietà con lo stesso nome dei nodi, alla quale assegna il nodo figlio indicato dal numero fornito come parametro nel costruttore dell'oggetto.

Ora, questa proprietà, che ha il valore di un oggetto, viene immagazzinata nella variabile privata nodo.

Quindi questa proprietà viene usata ripetutamente, per quanti sono i nodi figli, per desumere il nome dei nodi figli e creare le relative proprietà con gli stessi nomi dei nodi figli.

Così, quando istanzio l'oggetto, posso usare direttamente il nome dei nodi come fossero delle semplici proprietà dell'oggetto:
function init(){
 Record=new record(0);
 alert(Record.nome[0].text);
 alert(Record.cognome[0].text);
 alert(Record.professione[0].text);
 alert(Record.figlio[0].text)
 alert(Record.figlio[1].text);
}
Devo mettere lo zero quando le proprietà non sono array, mentre quando lo sono, come nel caso della proprietà "figlio", devo specificare l'indice dell'array.
Provo a usare un risultato più "grafico" in modo da copiarlo e incollarlo qui.
function init(){
 Record=new record(0);
 document.write(Record.nome[0].text+" "+
 Record.cognome[0].text+" "+
 Record.professione[0].text+" "+
 Record.figlio[0].text+" "+
 Record.figlio[1].text);
 
 document.write("<br>");
 
 Record=new record(1);
 document.write(Record.nome[0].text+" "+
 Record.cognome[0].text+" "+
 Record.professione[0].text);
}
Ed ecco il risultato:
Ciccio Rossi rapinatore Giovanni Luigi
Giuseppe Verdi Musicista


Il fatto che il secondo record non abbia i campi "figlio" fa sorgere tutta una serie di interrogativi che vedrò di affrontare successivamente...

Metodo per cambiare il valore di un campo nel file XML

Bene. Ho messo a punto anche un metodo "cambia()" per il mio schema di oggetto atto alla manipolazione dei files XML.
function persona(num){
 var record=root.getElementsByTagName("persona")[num];
 
  this.nome=record.getElementsByTagName("nome")[0];
  this.cognome=record.getElementsByTagName("cognome")[0];
  this.professione=record.getElementsByTagName("professione")[0];
  this.figli=record.getElementsByTagName("figlio");
  this.cambia=function(campo,valore){
   record.getElementsByTagName(campo)[0].childNodes[0].nodeValue=valore;
   var fso=new ActiveXObject("Scripting.FileSystemObject");
   var path=document.location.pathname;
   path=path.substr(1,path.lastIndexOf("/"));
   path=path.replace(/%20/g," ");
   var f=fso.CreateTextFile(path+"data.xml",true);
   f.write(xmlDoc.xml);
   f.Close();
   fso=null;
  }
}
Funziona.

sabato 27 ottobre 2012

Creazione di oggetti per muoversi in un file XML

Un piccolo artifizio per facilitarsi la vita con le tabelle costruite intorno ai files XML.
C'è un oggetto che rappresenta il record, le cui proprietà sono rappresentate dai suoi childNodes, come se fossero tanti elementi di una tabella.
L'oggetto viene poi istanziato in base al numero ordinale.
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("data.xml");
var root=xmlDoc.documentElement;

function persona(num){
 var record=root.getElementsByTagName("persona")[num];
 
  this.nome=record.getElementsByTagName("nome")[0];
  this.cognome=record.getElementsByTagName("cognome")[0];
  this.professione=record.getElementsByTagName("professione")[0];
  this.figli=record.getElementsByTagName("figlio");
}
function init(){
Mario=new persona(0);
Giuseppe=new persona(1);
alert(Mario.nome.text);
alert(Mario.cognome.text);
 for(var n=0;n<Mario.figli.length;n++)
  alert(Mario.figli[n].text);
}
window.onload=init;
costruito per questo XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tabella [
<!ELEMENT tabella (persona*)>
<!ELEMENT persona (nome, cognome, professione,figlio*)>
<!ELEMENT nome (#PCDATA)>
<!ELEMENT cognome (#PCDATA)>
<!ELEMENT professione (#PCDATA)>
<!ELEMENT figlio (#PCDATA)>
]>
<tabella>
 <persona>
  <nome>Mario</nome>
  <cognome>Rossi</cognome>
  <professione>Ladro</professione>
  <figlio>Giovanni</figlio>
  <figlio>Luigi</figlio>
 </persona>
 <persona>
  <nome>Giuseppe</nome>
  <cognome>Verdi</cognome>
  <professione>Musicista</professione>
 </persona>
</tabella>


Mi sembra molto funzionale, perchè istanziando volta per volta l'oggetto si può accedere a tutti i record della "tabella" e prenderne i campi desiderati come proprietà dell'oggetto.

lunedì 22 ottobre 2012

Elementi XML: dichiarazione del numero dei figli

La logica dell'XML è ferrea, a quanto pare!
Ho un file XML di questo genere:
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
</documento> 
E con il codice javaScript:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[0].text);
...riesco a caricarlo e a ottenere, come fatto prima, il messaggio "ciao merdaccia".
Adesso provo ad aumentare il numero degli elementi %lt;controllo> nel file XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
...e con quel codice javaScript non ottengo nulla, ma il debugger mi dà il messaggio di errore:
Impossibile ottenere il valore della proprietà 'getElementsByTagName': 
oggetto nullo o non definito


Perchè?

L'ho scoperto subito: perchè quando io specifico i figli dell'elemento <documento> uso la seguente sintassi:
<!ELEMENT documento (capitolo)>
che significa che l'elemento documento ha un solo figlio, mentre poi, di fatto, ne ha due.

Allora metto il simbolo +, che significa "uno o più figli":
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo+)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
e ottengo di nuovo l'insulto di prima, regolarmente, perchè adesso si specifica che i figli dell'elemento documento possono essere uno o più.
Adesso uso il simboletto ? che significa "zero o uno figli".
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo?)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
e non ottengo niente, perchè qui i figli sono due!
Provo infine a usare il simboletto *, che significa "zero o più":
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo*)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
E ottengo il mio caro "ciao merdaccia", oppure, se chiedo il contenuto del secondo elemento:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[1].text);
ottengo un meraviglioso "ciao deficiente"!
Nonostante gli insulti, sono contento!!!

Il mio primo caricamento di un file XML

BENE! Sono riuscito a caricare un file xml elementare in un documento HTML.
La sintassi in IE è questa:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[0].text);
Ho caricato questo file xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
</documento> 
E ho ottenuto una finestra di messaggio con scritto "ciao merdaccia".
Ottimo!!!

DTD

Saltiamo subito al sodo.
Analizziamo quella diavoleria che si trova all'inizio di un DTD.
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>  
Che cosa sono quegli ELEMENT preceduti dai punti esclamativi?
Significano rispettivamente che:
  • l'elemento note contiene altri elementi to, from, heading, body;
  • l'elemento to è un #PCDATA, come tutti gli altri elementi.
Che accidenti significa #PCDATA?

Meglio che mi eserciti perchè le cose si imparano meglio con la pratica...

XML

Prendo questo tutorial e me lo studio...

"If you need to display dynamic data in your HTML document, it will 
take a lot of work to edit the HTML each time the data changes.

With XML, data can be stored in separate XML files. This way you 
can concentrate on using HTML/CSS for display and layout, and be 
sure that changes in the underlying data will not require any 
changes to the HTML.

With a few lines of JavaScript code, you can read an external 
XML file and update the data content of your web page."

E' proprio quello che mi serve.


Bene, posso creare i miei tags come e quando voglio.
Ma come li uso?


Questa "intestazione", cosa è?
<?xml version="1.0" encoding="ISO-8859-1"?>
The first line is the XML declaration. It defines the 
XML version (1.0) and the encoding used (ISO-8859-1 = 
Latin-1/West European character set).
La dichiarazione XML inizia con un punto interrogativo, chissà perchè...
Poi c'è la versione. E quindi un encoding.

Cosa significa questo?

version è la versione xml, mentre encoding è il set di caratteri in cui è scritto l'xml...
Ah, ecco, spicchiamo il volo!
Ci sono slcuni tipi di files: il documento xml, che deve essere ben formato, e questo lo sapevamo, e valido.
Che significa valido?

A "Valid" XML document is a "Well Formed" XML document, which 
also conforms to the rules of a Document Type Definition (DTD)
Ecco: valido significa che si conforma alle regole di un DTD (definizione del tipo di documento).
Quindi ci deve essere un DTD, che dobbiamo creare a parte.
Ecco, sto ricominciando a "quagliare" le nozioni che avevo appreso un tempo e poi abbandonato per noia in quanto, siccome questo XML apparentemente non "fa" niente, era più bello trafficare con le pagine HTML e con il javaScript che permettono di ottenere risultati di "effetto"!
Un po' come il solfeggio per gli studenti di musica, che non vedono l'ora di "suonare" e sbuffano non poco su quel noioso esercizio, il quale, però, fornisce uno dei fondamenti di base per imparare a leggere la musica, tanto che se non avessi fatto solfeggio non sarei in grado di leggere una musica scritta su uno spartito come riesco a farlo abitualmente!

lunedì 8 ottobre 2012

Razionalizzazione degli antenati

Il programma va ulteriormente razionalizzato.

Risaliamo al capostipite.
Ogni parte della sezione deve avere un suo preciso attributo name. La mia sezione sarà formata da:
  • Container (il capostipite);
  • Notizie;
  • Lista;
  • Risultati
Dal capostipite si va a ogni elemento mediante il querySelector Ho implementato la funzione che individua il capostipite rispetto a ciascun oggetto della sezione:
function Container(e){
 var oggetto=e;
 while(oggetto.getAttribute("name") !="Container") {  
  oggetto=oggetto.parentNode;
 }
 return oggetto;
}


Ed ecco implementata la prima delle funzioni che dal capostipite discendono ai singoli discendenti individuandoli per nome:
function Notizie(e){
 var oggetto=Container(e).querySelector("[name='Notizie']");
 return oggetto;
}
E' fatta! Il programmino può essere ben razionalizzato!!!

Struttura generale della sezione del mio programma

Composizione di una sezione: Ho un contenitore.
Dentro questo contenitore ci sono quattro elementi, chiamati:
  • notizie
  • lista
  • risultati
  • pulsanti
Dunque l'innerHTML di contenitore è questo:
"<div class=giallochrosso>"+risposta+"</div>  
<div name='notizie' class=bordatoblu><textarea style='width:290px'></textarea>
</div>
<div name='lista' class=bordatoblu><input type='button' value='Aggiungi Blocco' onClick='aggiungiBlocco(this)'>
</div>  
<div name='risultati' class=bordatoblu>
</div>  
<div name="pulsanti" style='clear:left'><center><input type='button' value='NUOVO'onClick='aggiungiSezione()'>  <input type='button' value='DIMESSO' onClick='eliminaSezione(this)'></center>
</div>" 
I pulsanti sono:
  • Il pulsante "NUOVO", che aggiunge una nuova sezione
  • il pulsante "DIMESSO" che elimina la sua stessa sezione
  • il pulsante "AGGIUNGI BLOCCO" che aggiunge un blocco all'elemento "lista"
Dunque devo creare le funzioni chiamate da ognuno di questi pulsanti.

venerdì 5 ottobre 2012

Il figlio fantasma di HTML...

Ah! Ecco! Ma tu guarda...
Se faccio così
<html>
<head>
<script>
function mostra(){
 for(n=0;n<document.childNodes[0].childNodes.length;n++)
 {
  alert(document.childNodes[0].childNodes[n].nodeName);
 }
}
window.onload=mostra;
</script>
</head><body>
</body>
</html> 
mi sparisce quel #text e ottengo:
  • HEAD
  • BODY
Forse nel documento di testo che ho usato, sono andato a capo, o ho lasciato uno spazio che poi ho tolto, e così facendo ho creato un figlio "testo" per HTML.

i figli di HTML, figlio di document.

Ecco, ora vado avanti a vedere chi sono i figli di HTML.
<html>
<head>
<script>
function mostra(){
 for(n=0;n<document.childNodes[0].childNodes.length;n++)
 {
  alert(document.childNodes[0].childNodes[n].nodeName);
 }
}
window.onload=mostra;
</script>
</head>
<body>
</body>
</html> 
E qui c'è un'incognita! Mi restituisce HEAD, #text e BODY
Che accidenti è quel #text?

Iniziamo a vederci chiaro tra padri e figli nel DOM

Procediamo per ordine.
<html>
<head>
<script>
function mostra(){

 alert(document.childNodes[0].nodeName);
}
window.onload=mostra;
</script>
</head>
<body>


</body>
</html> 
...mi restituisce HTML.
Questo significa che il figlio di document è HTML.
document ha un figlio solo, come dimostrato da questo codice:
<html>
<head>
<script>
function mostra(){

 alert(document.childNodes.length);
}
window.onload=mostra;
</script>
</head>
<body>


</body>
</html> 
...che restituisce 1.

Quindi: document ha un solo figlio che è HTML.