Gestione di un questionario (originariamente memorizzato in un DB) in XML Memorizzazione di un questionario in un DB (MySQL) Consideriamo il problema di memorizzare un semplice questionario, che si proponga di erogare domande a risposta chiusa con una scelta multipla. Il modello descritto non considera la possibilità di registrare le risposte o tener conto dell utente (identificazione dell utente tramite login), perciò il questionario viene svolto in modo anonimo e quindi, si presume, a scopo di puro esercizio. Per gestire un semplice sistema di erogazione di tali quiz, dovranno essere presenti almeno due componenti software, il DBMS, contentente a sua volta il DB, che conterrà le domande e risposte e il programma (per noi uno script in PHP), che permetterà di erogarle e di raccogliere la risposta dell utente e verificare e segnalare se essa sia corretta o meno. Per gestire un simile tipo di sistema per erogare quiz, basta una sola tabella suddivisa nei seguenti campi: Id (identificatore univoco del quiz) Testo domanda Risposta 1 Risposta 2 Risposta 3 Risposta 4 Corretta Ossia sarà presente nella tabella il testo della domanda, i testi delle varie possibili risposte, e l indicazione della risposta corretta, di solito come numero intero, limitato in questo caso tra 1 e 4. Erogato il quiz, opportuno codice PHP mostrerà sia la domanda che le possibili risposte e l utente dovrà dare la sua risposta (se siamo in presenza di una interfaccia grafica solitamente sotto forma di una selezione su una serie di radiobutton), e questo permetterà al programma di verificare se essa sia corretta o errata. Ulteriori varianti di erogazione di simili quiz, potrebbero prevedere che venga data la possibilità di una seconda risposta oppure definire un limite di tempo entro cui la risposta deve essere data, ecc. Nello script qui presentato, si è realizzata la versione più semplice di tale erogazione (una sola risposta, senza limite di tempo). La singola tabella sopra accenata può essere strtturata concretamente come SQL in 1 : CREATE TABLE `quesiti` ( `Id_quiz` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `Domanda` VARCHAR(200) NOT NULL, `Risposta1` VARCHAR(100) NOT NULL, `Risposta2` VARCHAR(100) NOT NULL, `Risposta3` VARCHAR(100) NULL DEFAULT NULL, `Risposta4` VARCHAR(100) NULL DEFAULT NULL, `Corretta` TINYINT(4) NOT NULL, PRIMARY KEY (`Id_quiz`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB AUTO_INCREMENT=4; Il comando CREATE TABLE, indica il nome della tabella che andrà creata, successivamente all interno delle parentesi i vari campi di cui è composta la tabella (ossia quelli considerati prima), ed il relativo tipo di dato 1 Le specifiche in fondo al comando CREATE TABLE, si riferiescono al set di caratteri usato dal DB, all engine utilizzato dal DB (MySQL può utilizzare diversi engine per gestire i DB ognuno dalle diverse caratteristiche), ed in fondo, a che numero deve riprendere il contatore di conteggio nel caso di duplicazione / rigenerazione del DB stesso. Pagina 1
in essi contenuti, e se essi ammettano o no valore NULL. Per gli ultimi due campi si ammette valore NULL, in quanto le alternative di una generica domanda potrebbero prevedere anche la scelta Si / No, ossia tra due alternative e quindi Risposta3 e Risposta4 sarebbero NULL. Infine è presente il campo per indicare quale tra le risposte indicate sia quella corretta (campo Corretta), e l indicazione che il campo Id_Quiz sia chiave primaria ( definito dal comando PRIMARY KEY(...) ). La risposta dell utente verrà confrontata con il valore del campo Corretta, di tipo intero corto (TINYINT - 1 byte con segno, -128 -> 127). Gli altri campi sono di tipo alfanumerico dovendo memorizzare i testi delle risposte. Gli esempi non prevedono uno script per il caricamento, ma quindi che i quiz siano già caricati a mano, attraverso una opportuna interfaccia (magari grafica, come HeidiSQL) verso MySQL. Una ovvia possibilità è che si usufruisca del questionario direttamente dal DB stesso, estraendone ed utilizzandone opportunamente i dati. Un altra possibilità è che si trasformi il questionario in un file XML ed in base ad esso si eroghino le domande e le risposte. In pratica la struttura logica contenuta nella tabella del DB, può essere facilmente trasposta e riscritta come documento XML. Trasformazione del DB quiz in file XML Con un opportuno script PHP (indicato nel gruppo di file del modellino come riempi_quiz.php), il contenuto del DB può quindi essere trasposto in un file XML. Una possibile struttura di un file XML atto a contenere la struttura logica di questo DB potrà essere: <?xml version="1.0" encoding="utf-8"?> <questionario> <quiz id="1"> <domanda>... </domanda> <risposta1>...</risposta1> <risposta2>...</risposta2> <risposta3>...</risposta3> </risposta4> <corretta>2</corretta> </quiz> <quiz id="2">... </quiz> </questionario> Si osservi che tutti i tag sono racchiusi dai tag <questionario..., che è il tag root del documento XML. Sotto di esso vi sono diversi tag <quiz... che descrivono i vari quiz che compongono il questionario. Tali tag hanno ulteriori sottotag, indicanti le vari parti di un quiz descritte dalle colonne della tabella. Il contenuto di ognuno dei campi del DB viene trasposto come contenuto di questi tag. Si noti che la risposta 4 che risulta non presente viene rappresentata nel documento XML con un tag aperto/chiuso, ossia con contenuto nullo. Subito dopo si apre la sezione di documento relativa ad un nuovo quiz, delimitato da un tag <quiz, il quale ha un attributo id, indicante l id dello specifico quiz. Per portare i contenuti del DB nel documento XML, si dovrà: 1. Aprire una connessione verso il DBMS 2. Selezionare il DB 3. Effettuare una query che selezioni tutti i dati della tabella (SELECT * FROM Quesiti) 4. Ciclare sul recordset così ricavato per leggere i vari dati Pagina 2
5. Inserire i dati letti nel documento XML Il codice PHP che implementa i punti 1 e 2 è semplice: mysql_connect("localhost","root",""); mysql_select_db("db_xml"); Il punto 3 è eseguito grazie all istruzione: $rs = mysql_query("select * FROM Quesiti"); A questo punto si ottiene l insieme di record $rs, che dovrà essere scandito via codice; per scansirlo si inizia a leggere il recordset una linea (un record) alla volta, tramite l istruzione: $riga = mysql_fetch_array($rs); Che permette di estrarre una nuova riga ($riga) dall insieme di righe $rs. Una volta estratto il singolo record, l accesso ai campi di cui è costituito avviene come accesso ad elementi di array associativo, ove le chiavi sono il nome dei singoli campi e i valori sono ovviamente i contenuti dei campi stessi. $id = $riga['id_quiz']; $domanda = $riga['domanda']; $risposta1 = $riga['risposta1']; $risposta2 = $riga['risposta2']; $risposta3 = $riga['risposta3']; $risposta4 = $riga['risposta4']; $corretta = $riga['corretta']; A questo punto ottenuti tutti i dati del singolo quiz, è possibile trasporli opportunamente nel documento XML; considerato quindi il nodo root rappresentato dal tag <questionario..., si vanno ad aggiungere a questo un nuovo sottonodo (un ulteriore quiz), al quale viene associato un attributo ed il suo valore, poi a questo nodo appena creato (rappresentante il quiz nel suo complesso), verranno aggiunti tag figli che descrivano i valori delle singole componenti del quiz (la domanda, le risposte, la risposta corretta). $nuovo = $root->addchild("quiz"); $nuovo->addattribute("id",$id); $nuovo->addchild("domanda", $domanda); $nuovo->addchild("risposta1", $risposta1); $nuovo->addchild("risposta2", $risposta2); $nuovo->addchild("risposta3", $risposta3); $nuovo->addchild("risposta4", $risposta4); $nuovo->addchild("corretta", $corretta); queste operazioni vengono svolte in modo ciclico riempendo il documento di tutte le informazioni relative a tutti i quiz presenti nel questionario: while ($riga) (... operazioni di composizione del documento XML...) $riga = mysql_fetch_array($rs); } L istruzione in evidenza all interno del ciclo serve a ricavare ad ogni ciclo un nuovo record da elaborare. Il ciclo termina quando la lettura del record rende il valore booleano false. Pagina 3
Erogazione di un questionario strutturato in XML Per rendere utilizzabile il questionario (leggendolo dal documento XML appena creato) in ogni caso è necessario del codice (script eroga_questionario.php) del tutto diverso di quello utilizzato per trasporre i dati dal DB in un documento XML. Tale codice infatti, effettua una scrittura del documento XML, mentre il codice che và ad erogare i quiz deve ovviamente leggere, e non alterare, il documento XML stesso. Presupposta la presenza di un file XML derivato dal DB, o comunque già esistente nel formato indicato, consideriamo ora quindi il codice per poter erogare i quiz definiti da tale file XML. Innanzitutto si dovrà caricare il file XML di modo da averne a disposizione la struttura XML stessa: $root = simplexml_load_file("quiz_pieno.xml"); La disponibilità della struttura XML è derivata dall avere accesso al nodo root, dal quale è possibile accedere a tutti i suoi sottonodi. I sottonodi di primo livello sono come noto i quiz stessi. E possibile in PHP iterare sull insieme dei sottonodi grazie al ciclo foreach nella forma: foreach($root as $quiz)... Ogni nodo di tipo quiz a sua volta è costituito da sottonodi diversificati di cui abbiamo già parlato poco prima; A tali nodi essendo di nome ben definito è possibile anche accedere direttamente con la forma $quiz-><nomesottonodo> In tal modo via via che si scandiscono i vari quiz è possibile ricavarne i valori dei campi con l accesso al contenuto stesso; ciò è necessario anche per mostrare gli effettivi testi della domanda e delle risposte: echo "\n"; echo $quiz->domanda. "\n\n"; echo "1-". $quiz->risposta1. "\n"; echo "2-". $quiz->risposta2. "\n"; if ($quiz->risposta3-> tostring()!= "") echo "3-". $quiz->risposta3. "\n"; if ($quiz->risposta4-> tostring()!= "") echo "4-". $quiz->risposta4. "\n"; le ultime due stampe sono condizionate, perchè se il testo non è presente per le risposte 3 e 4 non devono apparire neppure gli indicatori numerici. Subito dopo aver proposto le varie scelte si passa a rilevare la risposta di chi stà svolgendo il quiz. Essa sarà data, nel nostro caso, tramite un input testuale, essendo l interfaccia del nostro script a carattere e non grafica: echo "\nrisposta? "; $risp = trim(fgets(stdin)); Lo script non prevede, nel nostro codice, un controllo di casi in cui la risposta sia al di fuori dei valori previsti tra cui scegliere. Subito dopo lo script controlla se il valore inserito dall utente sia uguale a quello presente nel campo che indica la risposta corretta (accessibile con $quiz->corretta); in un caso ovviamente dà risposta che è stato individuata la risposta corretta, nell altro l output indica che la risposta è errata: if ($risp == $quiz->corretta) echo "Bravo hai risposto correttamente!\n"; else eval("\$r = \$quiz->risposta". $quiz->corretta. ";"); echo "No. La risposta corretta era ". $r."\n"; } Pagina 4
Una spiegazione per l uso e la sintassi della funzione eval(...). La eval(...) presente con tale nome in molti linguaggi interpretati, permette di valutare (evaluate appunto) una espressione di codice nel linguaggio stesso (in questo caso in linguaggio PHP). Da notare che: Il simbolo $, per essere intepretato come carattere e non come variabile in una stringa, deve avere anteposto lo \. In questo modo esso diviene davvero il carattere $ in quella stringa. Nella eval è possibile ovviamente effettuare anche assegnazioni ad una variabile, in questo caso una assegnazione ad una variabile detta $r. L espressione... \$quiz->risposta. $quiz->corretta. ;, stà ad indicare il valore di una delle risposte e precisamente di quella corretta. In pratica la stringa nella eval stessa viene composta così che stia ad indicare l accesso al valore di risposta1, risposta2, ecc, a seconda di quale numero viene accodato alla prima parte. Ad esempio se la risposta corretta fosse la 3, la stringa che rappresenta l espressione PHP da valutare diverrà: $r = $quiz->risposta3; con il suo ovvio significato, ossia mettere in $r il contenuto della risposta corretta (nel caso ipotizzato la 3). Successivamente viene stampata una scritta indicante tale risposta corretta, assieme ad un messaggio che indica all utente che ha sbagliato risposta. Infine ad ogni nuovo quiz c è l attesa di un tasto prima di continuare, di modo da erogare i quiz in modo frazionato e non tutti assieme: echo "Premi un tasto per continuare...\n"; exec("pause"); L erogazione del questionario si realizza ciclando queste operazioni, rispondendo alle domande selezionando una opportuna risposta, finchè tutti i quiz non siano stati letti dal documento XML e svolti. Prof. Alberto Veneziani Pagina 5