7 Elaborazione di dati XML con PHP

Transcript

7 Elaborazione di dati XML con PHP
PHP_CAP07.qxd
19/05/2006
7
11.14
Pagina 163
Elaborazione di dati XML
con PHP
Nei precedenti capitoli è stata illustrata l’elaborazione di dati XML sul lato client utilizzando lo standard DOM e il linguaggio XSLT. Verrà ora descritto come elaborare dati
XML sul lato server utilizzando strumenti quali SAX, DOM e SimpleXML.
In linea di massima, esistono due modi per gestire l’elaborazione di dati XML: lo standard DOM (Document Object Model), che è stato già illustrato, e la tecnologia SAX
(Simple API for XML). Lo standard DOM consente di creare una struttura ad albero
gerarchica alla quale è possibile fare riferimento ripetutamente. Con SAX, i documenti
XML vengono gestiti come una serie di eventi, un evento per ciascun elemento o attributo, e la risposta a questi eventi viene fornita durante l’analisi del documento.
Naturalmente, ogni approccio presenta i propri vantaggi e svantaggi. Il modello DOM, ad
esempio, crea strutture ad albero che richiedono un uso esteso della memoria, ma una
volta create, fornisce numerosi strumenti per spostarsi, elaborare e manipolare queste
strutture ad albero. La tecnologia SAX consente una gestione lineare dei documenti XML,
quindi si tratta di una tecnologia meno flessibile, ma che è anche più semplice e rapida da
apprendere.
PHP 5.0 fornisce un terzo approccio alla gestione dei documenti XML, un approccio che
nel corso di questo manuale è stato già adottato. SimpleXML crea una struttura di oggetti
gerarchica simile al modello DOM. La differenza sta nel fatto che questa struttura viene
ottimizzata per l’estrazione e l’elaborazione delle informazioni, mentre il modello DOM
fornisce una API più efficace, per un uso più generale, per manipolare la composizione
della struttura ad albero.
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 164
Capitolo 7: Elaborazione di dati XML con PHP
In questo capitolo verranno illustrati, nell’ordine riportato, SAX, DOM e SimpleXML. Al
termine, si disporrà di una buona conoscenza del modo in cui è possibile utilizzare le
diverse API per gestire documenti XML.
Utilizzo di SAX
Si immagini di creare un documento XML, quindi di scomporlo nelle singole parti e
disporre queste parti come in una catena di montaggio. In tal modo, è possibile vedere
istruzioni di elaborazione, tag di inizio, contenuto, tag di fine e così via, ossia tutti gli elementi che compongono il documento sistemati all’interno di un’unica lunga riga.
Si preme un pulsante e il documento comincia a spostarsi lungo la catena di montaggio
sotto l’attenta sorveglianza di un omino con un megafono. I singoli elementi del documento (un commento, un’entità, un’istruzione di elaborazione oppure un blocco di testo)
scorrono l’uno dopo l’altro e la loro presenza viene annunciata di volta in volta dall’omino con il megafono. Questo è più o meno ciò che accade con il parser SAX.
Sfortunatamente, per poter fare qualcosa di interessante con SAX, occorre creare manualmente funzioni personalizzate per gestire i tag di inizio, i tag di fine e i dati di tipo character, eseguendo un’azione immediata in risposta a ciascun di essi. Se si desidera
memorizzare informazioni dal documento in una struttura dati temporanea da utilizzare
successivamente, è bene ricordare che SAX non esegue questa operazione. Non per altro
si tratta di un’API semplice per XML!
E allora, per quale motivo si dovrebbe utilizzare questo parser? L’uso di SAX risulta conveniente nelle seguenti situazioni:
❑ Si sta gestendo un documento XML di grandi dimensioni che se trasformato in una
struttura DOM richiederebbe una quantità eccessiva di memoria.
❑ Occorre attivare ed eseguire il parser rapidamente.
❑ Si sta eseguendo un’attività di elaborazione limitata oppure si sta eseguendo un tipo
di elaborazione molto semplice e lineare (ad esempio, la conversione di determinati
elementi XML in elementi HTML).
❑ Non occorre modificare il documento XML originale.
Nelle circostanze appropriate come, ad esempio, un documento XML di grandi dimensioni, è sicuramente più opportuno utilizzare SAX che non DOM. Tuttavia, è importante
comprendere che in alcuni casi, che verranno illustrati a breve, è più appropriato utilizzare una struttura ad albero.
164
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 165
Utilizzo di SAX
Il parser SAX predefinito per PHP è Expat[1], una libreria C affidabile e testata, che per
impostazione predefinita viene abilitata nella maggior parte delle installazioni PHP. Non
occorre installare altre librerie: tutto è già stato creato in PHP. Di seguito ne viene
descritto l’uso analizzando i singoli passi di una breve esercitazione.
Il primo passo consiste nel creare un semplice file XML per l’elaborazione. Il file che verrà
utilizzato in questa sezione è il seguente:
Esempio 7.1. keyword-data.xml
<?xml version=”1.0” encoding=”iso-8859-1”?>
<keywords>
<keyword>XML</keyword>
<keyword>PHP</keyword>
<keyword>Perl</keyword>
<keyword>JavaScript</keyword>
<keyword>ASP</keyword>
</keywords>
A questo punto, è possibile creare del codice PHP. Tuttavia, sarebbe opportuno, prima di
iniziare, avere già un’idea del risultato finale che si desidera conseguire. In questo caso
specifico, si desidera trasformare questo elenco di elementi di parole chiave in un elenco
puntato HTML, come illustrato nella Figura 7.1, “Elenco di parole chiave elaborato
mediante SAX”.
Figura 7.1. Elenco di parole chiave elaborato mediante SAX
[1] http://expat.sourceforge.net/
165
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 166
Capitolo 7: Elaborazione di dati XML con PHP
Creazione di gestori
Prima di poter proseguire, occorre creare funzioni che “gestiscano” i tag di inizio, i tag di
fine e i dati di tipo character. Queste funzioni verranno richiamate dal parser SAX mentre
elabora il documento XML.
Il primo gestore, a cui verrà assegnato il nome start_element, sarà responsabile della
gestione di tutti i tag di inizio contenuti nel documento XML. È possibile scegliere per
questo gestore il nome che si desidera; i nomi assegnati ai singoli gestori verranno poi
comunicati a PHP.
La funzione gestore per i tag di inizio deve accettare tre argomenti: un riferimento al
parser SAX (che verrà creato a breve), il nome dell’elemento il cui tag di inizio è stato rilevato e un array di attributi dell’elemento (e dei relativi valori).
Come è possibile notare di seguito, in questo caso il gestore non è altro che un’istruzione
switch che ricerca un nome di un tag XML e che risponde emettendo il codice HTML
appropriato.
Esempio 7.2. saxdemo.php (estratto)
function start_element($parser, $element_name, $element_attrs) {
switch ($element_name) {
case ‘KEYWORDS’:
echo ‘<h1>Keywords</h1><ul>’;
break;
case ‘KEYWORD’:
echo ‘<li>’;
break;
}
}
In SAX tutti i nomi dei tag sono maiuscoli
Per impostazione predefinita, il parser SAX in PHP esegue un processo chiamato
case folding, in cui qualsiasi carattere minuscolo contenuto nei nomi degli attributi
o dei tag viene sostituito con l’equivalente maiuscolo. Questo è il motivo per il quale
i nomi degli elementi ‘KEYWORDS’ e ‘KEYWORD’ in questo esempio sono tutti in maiuscolo. Qualora si desideri disabilitare il case-folding, il manuale di PHP contiene
informazioni[2] su come eseguire questa operazione.
[2] http://www.php.net/xml#xml.case-folding
166
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 167
Creazione del parser ed elaborazione del documento XML
Al prossimo gestore verrà assegnato il nome end_element. Questo gestore viene richiamato per rispondere ai tag di fine presenti nel documento e utilizza la stessa istruzione
switch che è stata introdotta precedentemente per emettere il codice HTML appropriato
quando i singoli tag di fine vengono rilevati.
Esempio 7.3. saxdemo.php (estratto)
function end_element($parser, $element_name) {
switch ($element_name) {
case ‘KEYWORDS’:
echo ‘</ul>’;
break;
case ‘KEYWORD’:
echo ‘</li>’;
break;
}
}
Infine, occorre trovare un modo per gestire i dati di tipo character. A tale scopo, viene
creata una funzione character_data che visualizzi il valore di ciascun nodo che rileva. È
bene ricordare che in XML, con “dati di tipo character” si indica tutto il testo che non sia
markup; questo gestore visualizza tutte le informazioni che si trovano tra i tag di inizio e
di fine di un elemento.
Esempio 7.4. saxdemo.php (estratto)
function character_data($parser, $data) {
echo htmlentities($data);
}
Dopo aver definito le funzioni personalizzate per la gestione del contenuto e dei tag, è
necessario creare un’istanza del parser.
Creazione del parser ed elaborazione
del documento XML
I passi successivi sono relativamente semplici, anche perché gran parte del lavoro viene
coordinata dalle funzioni di gestione appena create. Tutto ciò che occorre fare è creare il
parser e indicargli quali funzioni sono state create per gestire i tag di inizio, i tag di fine e
i dati di tipo character:
Esempio 7.5. saxdemo.php (estratto)
$parser = xml_parser_create();
xml_set_element_handler($parser, ‘start_element’, ‘end_element’);
xml_set_character_data_handler($parser, ‘character_data’);
167
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 168
Capitolo 7: Elaborazione di dati XML con PHP
Dopo aver fatto ciò, è possibile utilizzare la funzione PHP fopen standard per aprire il
documento XML:
Esempio 7.6. saxdemo.php (estratto)
$fp = fopen(‘keyword-data.xml’, ‘r’)
or die (“Cannot open keyword-data.xml!”);
Con il documento XML, è possibile utilizzare un semplice loop while per leggere blocchi
di codice gestibili (4 KB è una dimensione ragionevole) ed eseguirli attraverso il parser
con la funzione xml_parse. In caso di errore, viene utilizzata la funzione die di PHP per
visualizzare il messaggio di errore fornito da xml_error_string sulla base del codice di
errore fornito da xml_get_error_code. xml_get_current_line_number viene utilizzato per
puntare alla riga in cui si è verificato l’errore.
Esempio 7.7. saxdemo.php (estratto)
while ($data = fread($fp, 4096)) {
xml_parse($parser, $data, feof($fp))
or die(sprintf(‘XML ERROR: %s at line %d’,
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
Una volta terminato il loop, liberare il parser utilizzando xml_parser_free.
Esempio 7.8. saxdemo.php (estratto)
xml_parser_free($parser);
Per assimilare quanto illustrato finora, è opportuno ricapitolare tutte le singole attività
che sono state completate:
1. Creazione di gestori per tag di inizio, tag di fine e dati di tipo character.
2. Avvio del parser.
3. Registrazione dei gestori personalizzati con il parser.
4. Apertura del file XML.
5. Esecuzione di un loop nel file, inviando singoli blocchi di dati attraverso il parser.
6. Utilizzo della funzione di rilevazione errori incorporata per identificare eventuali
problemi.
7. Disimpegno del parser una volta completate tutte le operazioni.
Come è possibile notare, l’approccio SAX è molto semplice e chiaro. Tuttavia, non presenta alcune delle più efficaci funzioni che sono invece disponibili con altri approcci
come, ad esempio, il modello DOM.
168
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 169
Utilizzo di DOM
Utilizzo di DOM
In questa sezione verrà illustrato come opera la funzionalità DOM in PHP. Il modello
DOM è una tecnologia robusta e affidabile che consente di gestire svariate situazioni.
Infatti, il principale punto di forza di questo standard è proprio la sua grande flessibilità.
Per quanto concerne gli svantaggi, invece, è possibile citare l’estrema complessità, la
vastità e il fatto che, quando si carica in memoria un documento di grandi dimensioni,
può addirittura bloccare le risorse.
L’utilizzo di DOM sul lato client è stato già illustrato. Per quanto riguarda il lato server, il
DOM è un’interfaccia standardizzata. Il modo più semplice per illustrare l’utilizzo di
DOM sul lato server consiste nel confrontarlo con le caratteristiche di SAX descritte nella
sezione precedente. Come si è visto, è possibile utilizzare SAX per elaborare documenti
XML in maniera molto lineare.
La funzionalità DOM di PHP adotta un approccio differente. Carica un documento XML
in memoria e lo converte in una propria struttura gerarchica di oggetti, fornendo due
funzioni molto importanti che in SAX mancano. La prima è la possibilità di manipolare
la struttura XML in memoria, consentendo l’aggiunta, la rimozione, la modifica e la ridisposizione dei nodi. La seconda è quella che consente di esaminare il documento continuamente, con accesso casuale, e non solo in maniera lineare.
Per un confronto dettagliato dei due approcci, utilizzare di nuovo il file XML contenuto
nella sezione dedicata al parser SAX:
Esempio 7.9. keyword-data.xml
<?xml version=”1.0” encoding=”iso-8859-1”?>
<keywords>
<keyword>XML</keyword>
<keyword>PHP</keyword>
<keyword>Perl</keyword>
<keyword>JavaScript</keyword>
<keyword>ASP</keyword>
</keywords>
A questo punto, creare un parser DOM e caricare il file XML.
Creazione di un parser DOM
Per creare il parser, occorre creare un oggetto DOMDocument. Prima di utilizzarlo, è necessario disattivarne la funzione di gestione degli spazi vuoti per impedire che spazi, tab e
interruzioni di riga tra i tab vengano gestiti come nodi di testo:
169
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 170
Capitolo 7: Elaborazione di dati XML con PHP
Esempio 7.10. domdemo.php (estratto)
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
Successivamente, occorre caricare il documento XML e assegnare un riferimento all’elemento documento:
Esempio 7.11. domdemo.php (estratto)
$doc->load(“keyword-data.xml”);
$root = $doc->documentElement;
Recupero degli elementi
Dopo aver creato il parser e caricato il file XML, è possibile richiamare informazioni dal
documento. Uno dei modi più semplici di utilizzare il modello DOM consiste nel richiamare elementi servendosi del metodo getElementsByTagName.
Il metodo getElementsByTagName consente di acquisire tutti gli elementi contenuti in un
altro elemento che presentano un determinato nome. È possibile utilizzare questo
metodo per acquisire tutti i singoli elementi keyword nel documento di esempio e memorizzarli in un array:
Esempio 7.12. domdemo.php (estratto)
$keywords = $root->getElementsByTagName(‘keyword’);
Dal momento che il metodo è stato richiamato sull’elemento root del documento, l’array
$keywords contiene ora ogni singolo elemento keyword del documento XML. A questo
punto è possibile eseguire un’iterazione nell’array $keywords per assicurarsi che ciascun
elemento sia valido. Successivamente, è possibile eseguire attività di elaborazione su quell’elemento.
Esempio 7.13. domdemo.php (estratto)
echo ‘<ul>’;
foreach ($keywords as $kw) {
echo ‘<li>’ . htmlentities($kw->nodeValue) . ‘</li>’;
}
echo ‘</ul>’;
Il risultato viene visualizzato nel browser Web come illustrato nella Figura 7.2, “Esempio
di elaborazione di parole chiave”.
170
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 171
Recupero degli elementi
Figura 7.2. Esempio di elaborazione di parole chiave
Finora i risultati ottenuti sono praticamente gli stessi di quelli conseguiti con SAX. La differenza principale sta nell’approccio: in SAX, è stato necessario creare funzioni personalizzate che gestissero i vari tipi di tag mano a mano che venivano rilevati dal parser; con
DOM, invece, è possibile accedere ai diversi livelli della struttura gerarchica del nodo nell’ordine desiderato.
Per quanto concerne l’uso di XML e DOM, vi è ancora un altro aspetto da sottolineare.
Se si desidera modificare ciò che viene emesso come output oppure il formato delle
modifiche XML, di solito è preferibile eseguire queste modifiche in DOM piuttosto che
in SAX.
Ad esempio, si supponga che ciascuno degli elementi keyword disponga di un attributo
status, come riportato di seguito:
Esempio 7.14. keyword-data2.xml (estratto)
<?xml version=”1.0” encoding=”iso-8859-1”?>
<keywords>
<keyword status=”live”>XML</keyword>
<keyword status=”in progress”>PHP</keyword>
<keyword status=”live”>Perl</keyword>
<keyword status=”live”>Javascript</keyword>
<keyword status=”in progress”>ASP</keyword>
</keywords>
A questo punto, si desidera visualizzare l’attributo status di keyword insieme alla parola
chiave. A tale scopo, occorre apportare solo una semplice modifica:
171
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 172
Capitolo 7: Elaborazione di dati XML con PHP
Esempio 7.15. domdemo2.php (estratto)
echo ‘<ul>’;
foreach ($keywords as $kw) {
echo ‘<li>’ . htmlentities($kw->nodeValue) .
‘ (‘ . htmlentities($kw->getAttribute(‘status’)) . ‘)</li>’;
}
echo ‘</ul>’;
Il risultato di questa piccola modifica viene illustrato nella Figura 7.3, “Modifica dell’elenco delle parole chiave”.
Figura 7.3. Modifica dell’elenco delle parole chiave
Per visualizzare solo le parole chiave “live”, è sufficiente aggiungere un semplice test if:
Esempio 7.16. domdemo3.php (estratto)
echo ‘<ul>’;
foreach ($keywords as $kw) {
if ($kw->getAttribute(‘status’) == ‘live’) {
echo ‘<li>’ . htmlentities($kw->nodeValue) . ‘</li>’;
}
}
echo ‘</ul>’;
Il risultato viene illustrato nella Figura 7.4, “Visualizzazione delle sole parole chiave ‘live’”.
172
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 173
Creazione di nodi
Figura 7.4. Visualizzazione delle sole parole chiave ‘live’
Creazione di nodi
Come evidenziato precedentemente, il modello DOM consente di aggiungere nuovi nodi
e di manipolare quelli esistenti. Creare, dunque, un nuovo elemento keyword e aggiungerlo
alla struttura DOM esistente.
È possibile aggiungere un nuovo nodo utilizzando il metodo create_element dell’oggetto
DOMDocument. A tale scopo è sufficiente passare il nome del nuovo nodo e, facoltativamente,
il relativo valore del nodo (il testo che dovrebbe contenere):
Esempio 7.17. domdemo4.php (estratto)
$newKW = $doc->createElement(‘keyword’, ‘XSLT’);
Successivamente occorre associare il nuovo nodo parola chiave alla struttura DOM. A tale
scopo, è possibile utilizzare il metodo appendChild, ma è necessario indicare a DOM il
punto esatto in cui si desidera aggiungere il nodo.
In questo caso specifico, è sufficiente aggiungere il nuovo elemento parola chiave alla
variabile $root stabilita (è bene ricordare che questa variabile rappresenta l’elemento root
del documento, in questo esempio, keywords).
Esempio 7.18. domdemo4.php (estratto)
$root->appendChild($newKW);
Con un documento modificato a disposizione, è possibile effettuare numerose operazioni. Una delle operazioni più comuni consiste nell’emettere l’output del codice XML
del documento modificato in un file sul server oppure in un browser Web.
173
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 174
Capitolo 7: Elaborazione di dati XML con PHP
Visualizzazione di codice XML da DOM
La visualizzazione di una struttura DOM come codice XML è piuttosto semplice. Infatti,
è sufficiente utilizzare il metodo saveXML della classe DOMDocument. Impostando come prima
cosa la proprietà formatOutput dell’oggetto su true, è possibile generare il codice XML desiderato.
Esempio 7.19. domdemo4.php (estratto)
$doc->formatOutput = true;
echo ‘<p>Updated XML source code:</p>’;
echo ‘<pre>’ . htmlentities($doc->saveXML()) . ‘</pre>’;
Questa rapida analisi ha illustrato in maniera molto generica la funzionalità del modello
DOM. Maggiori dettagli verranno forniti nel corso di questo capitolo e in quelli successivi, soprattutto quando sarà necessario ricorrere a questo modello per la creazione
immediata di documenti XML.
Utilizzo di SimpleXML
Prima dell’introduzione di SimpleXML in PHP 5, gli sviluppatori potevano manipolare
ed elaborare i documenti XML solo con SAX e DOM. Entrambi gli approcci erano consolidati e affidabili, ma il loro uso presupponeva una conoscenza approfondita da parte
dello sviluppatore dei processi che avrebbe creato.
Con SimpleXML, come implica il nome, si semplifica il modo in cui uno sviluppatore
PHP interagisce, elabora e manipola i dati XML. SimpleXML offre, infatti, grandi vantaggi. Sostanzialmente, SimpleXML carica i dati XML all’interno di una gerarchia di
oggetti e array di oggetti, quindi consente di accedere all’array utilizzando metodi familiari quali i loop foreach e gli indici di array.
In altre parole, gli sviluppatori di SimpleXML si erano resi conto che XML veniva utilizzato prevalentemente per l’estrazione e l’elaborazione di informazioni, quindi studiarono
un modo che rendesse più semplice eseguire questo tipo di operazioni.
Come è stato evidenziato nel Capitolo 4, Visualizzazione di XML in un browser,
SimpleXML assegna a ciascun tag presente in un file XML una proprietà che corrisponde
al relativo nome dell’elemento. Esaminare il seguente documento XML:
<document>
<msg>Hello</msg>
</document>
174
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 175
Caricamento di documenti XML
In questo caso è possibile accedere al valore del tag <msg> utilizzando la notazione freccia
orientata agli oggetti di PHP, come mostrato di seguito:
echo $xml->msg;
Le modifiche dei nomi degli elementi influiscono
sul codice PHP
Uno dei grandi svantaggi di questo approccio è rappresentato dal fatto che se, per
un qualsiasi motivo, i nomi degli elementi XML subiscono una modifica, sarà necessario ritornare indietro e modificare la logica SimpleXML perché vi sia corrispondenza con i nuovi nomi. Il modo migliore per evitare questo tipo di problemi
consiste nell’assicurarsi che i documenti XML siano definitivi e strutturati nella
maniera richiesta. Se si apportano modifiche ai documenti XML dopo aver iniziato
la codifica PHP, occorre intervenire anche nel codice per garantire la corrispondenza
con le nuove modifiche apportate.
Nelle sezioni successive verranno illustrate tutte le principali funzioni di SimpleXML.
Caricamento di documenti XML
Per utilizzare SimpleXML, come prima cosa occorre identificare il documento XML che
si desidera elaborare. SimpleXML può caricare un file in memoria oppure lavorare sul
codice XML sotto forma di una stringa PHP.
Per aprire un file, utilizzare la funzione simplexml_load_file come riportato di seguito:
Esempio 7.20. sxmldemo.php (estratto)
$keywords = simplexml_load_file(‘keyword-data2.xml’);
È anche possibile fornire il proprio XML come variabile, quindi caricare questa variabile
in memoria utilizzando la funzione simplexml_load_string:
Esempio 7.21. sxmldemo2.php (estratto)
$xml = <<<XML
<?xml version=”1.0” encoding=”iso-8859-1”?>
<keywords>
<keyword status=”live”>XML</keyword>
<keyword status=”in progress”>PHP</keyword>
<keyword status=”live”>Perl</keyword>
<keyword status=”live”>JavaScript</keyword>
<keyword status=”in progress”>ASP</keyword>
</keywords>
XML;
$keywords = simplexml_load_string($xml);
175
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 176
Capitolo 7: Elaborazione di dati XML con PHP
Dichiarazione di stringhe PHP con heredoc
La stringa PHP che contiene il codice XML nell’esempio sopra riportato viene
dichiarata utilizzando la sintassi heredoc. Coloro che non conoscono questa sintassi
possono consultare il manuale di PHP[3].
Indipendentemente dall’approccio utilizzato, il risultato sarà una gerarchia di oggetti e di
array chiamata $keywords. È ora possibile accedere alle diverse parti di questa struttura utilizzando la sintassi di array o di oggetti PHP standard.
Gerarchia degli elementi XML
Quando un elemento XML contiene più elementi figlio con lo stesso nome (come accade
per l’elemento keywords di questo esempio), questi elementi figlio vengono memorizzati
in un array nella gerarchia degli oggetti. Pertanto è possibile utilizzare indici di array per
accedere alle informazioni necessarie. Ad esempio, è possibile utilizzare la seguente sintassi per accedere alle varie parole chiave contenute nel documento XML:
echo $keywords->keyword[0]; // prints “XML”
echo $keywords->keyword[1]; // prints “PHP”
Si noti che, in ogni caso, si utilizza l’oggetto $keywords, che rappresenta l’elemento root del
documento, seguito dall’operatore freccia e dal nome del nodo figlio a cui si è interessati
(in questo caso, keyword). Poiché si tratta di un array, si utilizza keyword[0] per accedere al
primo elemento keyword. Per accedere al secondo, si utilizza keyword[1] e così via.
Per ottenere, invece, tutti i valori di un array di elementi XML creato da SimpleXML, è
possibile utilizzare un semplice loop foreach PHP:
Esempio 7.22. sxmldemo.php/sxmldemo2.php (estratto)
echo ‘<ul>’;
foreach ($keywords->keyword as $kw) {
echo ‘<li>’ . htmlentities($kw) . ‘</li>’;
}
echo ‘</ul>’;
Quando un elemento contiene solo un elemento figlio di un determinato tipo, non viene
creato alcun array. Infatti, è possibile accedere all’elemento direttamente. Si supponga che
il file XML che si sta utilizzando sia più complesso e che contenga un altro livello di elementi: nodi figlio di ciascun elemento keyword. Il file potrebbe risultare come riportato
di seguito:
[3] http://www.php.net/language.types.string#language.types.string.syntax.heredoc
176
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 177
Gerarchia degli elementi XML
<keywords>
<keyword status=”live”>
<name>XML</name>
<url>http://www.example.com/xml/</url>
</keyword>
<keyword status=”in progress”>
<name>PHP</name>
<url>http://www.example.com/php/</url>
</keyword>
…
</keywords>
Per visualizzare i valori degli elementi name e url per il primo elemento keyword, procedere come riportato di seguito:
echo $keywords->keyword[0]->name; // “XML”
echo $keywords->keyword[0]->url; // “http://www.example.com/xml/”
Come è possibile notare, il procedimento è davvero molto semplice. Infatti, è molto più
semplice lavorare con SimpleXML che non utilizzare una struttura DOM oppure dichiarare gestori SAX personalizzati.
Gli oggetti elemento SimpleXML possono essere utilizzati laddove sono richieste stringhe
e si comporteranno come tali, includendo il valore di testo contenuto nel corrispondente
elemento XML. Tuttavia, è importante ricordare che, di fatto, questi oggetti non sono
stringhe. Questa distinzione scatta nei casi in cui non è richiesta una stringa e pertanto
PHP non eseguirà la conversione. Segue un esempio:
if ($keywords->keyword[0] == ‘XML’) {
echo ‘The first keyword is XML.’;
}
Analizzando il documento XML di esempio ci si aspetterebbe che questa l’istruzione if
faccia eseguire l’istruzione successiva e visualizzare il messaggio, ma ciò non si verifica in
quanto $keywords->keyword[0] è un oggetto e come tale non è uguale alla stringa ‘XML’.
Perché questo codice si comporti come previsto, è necessario eseguire la conversione
attraverso l’esecuzione del cast dell’oggetto in una stringa:
if ((string)$keywords->keyword[0] == ‘XML’) {
echo ‘The first keyword is XML.’;
}
177
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 178
Capitolo 7: Elaborazione di dati XML con PHP
Se non si conosce bene PHP, potrebbe risultare alquanto difficile capire quando occorre
eseguire la conversione e quando invece questa operazione verrà eseguita da PHP. Gli
esempi contenuti in questo manuale dovrebbero chiarire questo aspetto, ma in caso di
dubbi, si consiglia di eseguire il cast del valore in una stringa: in tal modo, si avrà sempre
la certezza che PHP gestirà il valore nella maniera prevista.
Valori degli attributi XML
È possibile accedere al valore di un attributo gestendo l’oggetto elemento come array e
utilizzando il nome dell’attributo come chiave di array.
Ad esempio, per visualizzare il valore dell’attributo status del primo elemento keyword, è
possibile utilizzare la seguente istruzione:
echo $keywords->keyword[0][‘status’]; // prints “live”
Tuttavia, con i valori degli elementi, il discorso si complica quando si tenta di confrontare
valori degli attributi con stringhe PHP, in quanto sono fondamentalmente oggetti. Ad
esempio, si supponga di voler visualizzare solo parole chiave “live”. In tal caso, si potrebbe
procedere come riportato di seguito:
foreach ($keywords->keyword as $kw) {
if ($kw[‘status’] == ‘live’) { // wrong!
echo ‘<li>’ . htmlentities($kw) . ‘</li>’;
}
}
Questo frammento di codice sembra accettabile. Tuttavia, dal momento che PHP non
può eseguire il confronto di due entità diverse, in questo caso, oggetti e stringhe, nessuna
delle parole chiave verrà visualizzata.
Pertanto, è necessario eseguire il cast dell’oggetto attributo in una stringa:
Esempio 7.23. sxmldemo3.php (estratto)
foreach ($keywords->keyword as $kw) {
if ((string)$kw[‘status’] == ‘live’) {
echo ‘<li>’ . htmlentities($kw) . ‘</li>’;
}
}
In questo caso si è scelto di imboccare la strada più difficile. Tuttavia, grazie a Xpath esiste
un metodo più semplice per filtrare i valori che vengono richiamati da un documento
XML.
178
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 179
Query XPath
Query XPath
Esiste un altro modo per filtrare elementi XML basati sul valore di un attributo, che
implica l’uso del metodo xpath incontrato nel Capitolo 4, Visualizzazione di XML in un
browser. Come già evidenziato, questo metodo consente di passare query XPath in
SimpleXML e di ricevere i risultati sotto forma di array.
Il modo più semplice per acquisire tutti gli elementi keyword il cui attributo status sia
impostato su live consiste nell’eseguire la query XPath riportata di seguito dall’elemento
keyword nel documento:
keyword[@status=”live”]
Questa query esaminerà tutti gli elementi keyword che sono elementi figlio dell’elemento
corrente ed estrarrà tutti quelli il cui status sia live. Di seguito viene illustrato come effettuare questa operazione con SimpleXML:
Esempio 7.24. sxmldemo4.php (estratto)
foreach ($keywords->xpath(‘keyword[@status=”live”]’) as $kw) {
echo ‘<li>’ . htmlentities($kw) . ‘</li>’;
}
Ma quali sono i vantaggi che offre una query XPath? In primo luogo, non è più necessario
eseguire un confronto tra stringhe all’interno di PHP: questa operazione viene gestita da
XPath. Se si ha familiarità con lo sviluppo di database in PHP, questo tipo di operazione
equivale a consentire a una istruzione SQL di eseguire il filtraggio dei valori di database
prima di restituirli nello script. In secondo luogo, il codice risulta ora meno complesso e,
fortunatamente, anche più semplice da gestire.
Analizzando il secondo costrutto, si può ritenere questo approccio molto più complicato
che non eseguire il cast di un oggetto in una stringa per il confronto.
Tuttavia, la difficoltà e la semplicità di un approccio sono relative.
Utilizzo di SimpleXML per aggiornare
codice XML
Un altro dei grandi vantaggi offerti da SimpleXML è rappresentato dal fatto che consente
di aggiornare i valori in maniera molto semplice. Si supponga di voler modificare la terza
parola chiave dell’esempio da PHP a JSP. Di seguito viene mostrato come procedere:
179
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 180
Capitolo 7: Elaborazione di dati XML con PHP
$keywords->keyword[2] = ‘JSP’;
Per modificare il valore di un attributo, è sufficiente aggiungere il nome dell’attributo
appropriato come chiave di array:
$keywords->keyword[2][‘status’] = ‘live’;
Per salvare oppure visualizzare il codice XML aggiornato, utilizzare il metodo asXML:
echo $keywords->asXML();
Correzione di problemi SimpleXML con DOM
SimpleXML, pur nella sua semplicità ed eleganza, presenta alcuni svantaggi. In primo
luogo, non è possibile (al momento della scrittura) aggiungere nuovi nodi a un documento XML, ma solo modificare i valori di quelli esistenti. Non è possibile neppure eliminare nodi. Non è possibile associare fogli di stile al proprio XML per eseguire
trasformazioni. Infine, come è stato possibile notare, il codice PHP dipende fortemente
dai nomi dei tag XML: se questi vengono modificati, l’aggiornamento del codice può
essere una vera seccatura.
Ad ogni modo, SimpleXML dispone di una funzione davvero comoda che gli consente di
interoperare con altre funzionalità XML PHP. Precisamente, questa funzionalità permette
di importare documenti DOM e di convertirli in strutture di dati SimpleXML.
Ma quali sono i vantaggi? Questa funzionalità consente di attuare la parte più impegnativa della funzionalità DOM nativa in PHP; successivamente è possibile convertirla in
SimpleXML e completare il lavoro.
Per comprendere quanto appena illustrato attraverso un esempio pratico, caricare un
documento con DOM e apportarvi una modifica che non sarebbe possibile eseguire con
SimpleXML:
Esempio 7.25. sxmldemo5.php (estratto)
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->load(“keyword-data2.xml”);
$root = $doc->documentElement;
$newKW = $doc->createElement(‘keyword’, ‘JSP’);
$newKW->setAttribute(‘status’, ‘live’);
$root->appendChild($newKW);
Con un nuovo elemento aggiunto alla struttura DOM, è possibile utilizzare la funzione
simplexml_import_dom per importarlo in una struttura di dati SimpleXML. Successivamente,
180
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 181
Quando utilizzare i diversi metodi
è possibile utilizzare l’API SimpleXML per eseguire tutte le operazioni richieste: ad
esempio, ricercare e visualizzare nodi con un determinato valore di attributo.
Esempio 7.26. sxmldemo5.php (estratto)
$keywords = simplexml_import_dom($doc);
echo ‘<ul>’;
foreach ($keywords->xpath(‘keyword[@status=”live”]’) as $kw) {
echo ‘<li>’ . htmlentities($kw) . ‘</li>’;
}
echo ‘</ul>’;
Questo codice consente di visualizzare un elenco di parole chiave il cui status è live, compresa “JSP”, che è stata aggiunta utilizzando DOM.
Quando utilizzare i diversi metodi
A questo punto è lecito domandarsi quando è appropriato utilizzare SAX, DOM e/o
SimpleXML. Di seguito vengono elencate alcune regole generali:
❑ Nel caso di un documento XML molto semplice che richiede unicamente una elaborazione lineare e che non deve essere modificato, SAX rappresenta la scelta appropriata.
❑ Se occorre elaborare un documento XML più complesso, ma al solo scopo di estrarre
informazioni, SimpleXML rappresenta la scelta appropriata.
❑ Se occorre creare nuovi documenti XML oppure apportare modifiche sostanziali a
documenti esistenti, utilizzare DOM.
Progetto CMS
A questo punto è possibile creare le funzionalità di amministrazione del progetto CMS.
Gli strumenti di amministrazione di cui si dispone consentiranno agli utenti autorizzati
di collegarsi a CMS e di amministrare le varie parti del sito Web. Più specificamente, si
procederà alla realizzazione delle seguenti funzionalità:
❑ pagina di accesso/verifica
❑ indice amministrativo (da cui gli utenti di CMS possono accedere ad altre pagine)
❑ pagina per la creazione di nuovi articoli
181
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 182
Capitolo 7: Elaborazione di dati XML con PHP
❑ pagina per la modifica degli articoli
❑ pagina per l’eliminazione degli articoli
Dopo aver creato queste pagine, il discorso sullo strumento di amministrazione verrà
temporaneamente interrotto e ripreso poi nell’Appendice B, Strumento di amministrazione di CMS, in quanto gran parte delle informazioni è piuttosto ripetitiva e può essere
trattata in una sezione a parte. Questa trattazione include:
❑ pagine per la creazione/modifica/eliminazione di notizie
❑ pagine per la creazione/modifica/eliminazione di file binari
❑ pagine per la creazione/modifica/eliminazione di categorie
❑ pagine per la creazione/modifica/eliminazione di amministratori
Tutte le pagine dell’area di amministrazione si trovano nella directory admin del sito.
Disabilitazione della funzione magic quotes
Tutti gli script PHP presenti in questo libro presuppongono che la funzione magic
quotes di PHP sia disabilitata. Per disabilitare questa funzione, impostare l’opzione
magic_quotes_gpc contenuta nel file php.ini del proprio server su Off.
Se questa funzione viene lasciata attiva, quando si manipola il contenuto utilizzando
gli script di amministrazione che verranno sviluppati in questa sezione e
nell’Appendice B, Strumento di amministrazione di CMS, il contenuto presenterà
numerose barre rovesciate (\) indesiderate.
Pagina di accesso
La pagina di accesso è molto semplice. Si basa su un elementare form HTML che consente
agli amministratori di specificare il proprio nome utente e la propria password. Questo
form diventerà più complesso quando si strutturerà l’HTML in modo che possa essere
efficacemente stilizzato grazie all’applicazione di un CSS.
Esempio 7.27. login.php
<?php
session_start();
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>Please Log In</title>
<meta http-equiv=”Content-Type”
content=”text/html; charset=iso-8859-1”>
182
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 183
Pagina di accesso
<link rel=”stylesheet” type=”text/css” href=”../xmlcms.css” />
<link rel=”stylesheet” type=”text/css” href=”login.css” />
</head>
<body>
<form class=”login” action=”verify.php” method=”post”>
<h1>Please log in</h1>
<div class=”fields”>
<label for=”username”>User name</label>
<input type=”text” id=”username” name=”username” class=”text” />
<label for=”password”>Password</label>
<input type=”password” id=”password” name=”password”
class=”password” />
</div>
<div class=”actions”>
<input type=”submit” value=”Submit” />
<input type=”reset” value=”Reset” />
</div>
<p class=”error”><?php echo $_SESSION[‘error’]; ?></p>
</form>
</body>
</html>
Oltre al foglio di stile del sito di base (xmlcms.css), questa pagina utilizza un foglio di stile
specifico per il layout del form di accesso. Come già evidenziato in precedenza, non
essendo questo un manuale dedicato ai fogli di stile CSS, i dettagli relativi a questo file
verranno tralasciati, ma per una questione di completezza di seguito ne viene fornito il
codice:
Esempio 7.28. login.css
form.login {
width: 290px;
margin: 1em auto;
padding: 4px;
background: #ccc;
}
form.login h1 {
text-align: center;
font-size: medium;
background: #fff;
margin: 1px;
}
form.login .fields {
text-align: right;
}
form.login label {
float: left;
width: 130px;
text-align: right;
183
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 184
Capitolo 7: Elaborazione di dati XML con PHP
}
form.login .actions {
text-align: center;
}
form.login input.text, form.login input.password {
width: 150px;
margin-bottom: 1px;
}
form.login .error {
color: red;
margin: 0;
padding: 0;
}
Analizzando la pagina di accesso, è possibile notare che l’elemento action del form è
impostato su una pagina denominata verify.php. La logica PHP contenuta in questa
pagina deve verificare i valori immessi in un elenco di amministratori che si trova in
admin.xml.
Protezione dei file XML
Ai fini degli esempi proposti in questo manuale e per l’archiviazione del relativo
codice, i file XML in cui si trovano il contenuto, le categorie, gli autori e gli utenti
amministrativi sono stati inseriti in una sottodirectory del sito principale. Tuttavia,
per proteggere ulteriormente le informazioni riservate contenute in questi file come,
ad esempio, la crittografia delle password degli amministratori, fare in modo che i
visitatori occasionali del sito non abbiano accesso diretto a questi file.
Per proteggere questi file, è possibile configurare il server Web in modo che impedisca ai browser di accedere alla directory oppure è possibile spostare la directory
all’esterno della struttura di directory del sito accessibile dal Web. Nel secondo caso,
sarà necessario modificare il file common.inc.php perché punti alla nuova ubicazione della directory, in modo che tutti gli script del sito possano trovare i file XML.
Password crittografate
Come è stato possibile notare, i valori delle password memorizzati in admin.xml vengono crittografati, così da garantire maggiore protezione. Per utilizzare il file di
esempio admin.xml incluso nell’archivio del codice per questo libro, occorre sapere
che la password iniziale di tutti e tre gli amministratori memorizzata in quel file
(joe, bill e tom) è password.
In caso di corrispondenza, il codice PHP imposterà una variabile di sessione e reindirizzerà l’utente verso la pagina dell’indice di amministrazione. In caso contrario, PHP riporterà l’utente di nuovo alla pagina login.php, con una variabile di sessione speciale
($_SESSION[‘error’]) contenente un messaggio di errore da visualizzare.
184
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 185
Pagina di accesso
Il codice specifico viene riportato di seguito. Si noti che in questo caso si è scelto di utilizzare SimpleXML, in quanto è il metodo più veloce per caricare le informazioni da admin.xml.
Esempio 7.29. verify.php
<?php
include_once ‘../common.inc.php’;
$admins = simplexml_load_file($fileDir . ‘admin.xml’);
foreach ($admins->admin as $admin) {
if ($_POST[‘username’] == (string)$admin->username and
crypt($_POST[‘password’], (string)$admin->password) ==
(string)$admin->password) {
$_SESSION[‘login’] = true;
header(‘location: index.php’);
exit;
}
}
$_SESSION[‘error’] = ‘Wrong user name or password. Try again.’;
header(‘location: login.php’);
?>
Inoltre, quando vengono crittografate le password in admin.xml, occorre accettare la password fornita dall’utente, crittografarle allo stesso modo, quindi confrontare l’input
utente con la password memorizzata nel file XML. Se non si ha familiarità con la funzione
crypt di PHP, è possibile consultare il manuale di PHP[4].
Dal momento che chiunque può immettere un URL per una delle pagine di amministrazione, è necessario garantire per il contenuto di queste pagine una maggiore protezione.
Nella parte superiore di ciascuna pagina, occorre verificare se il valore della variabile di
sessione $_SESSION[‘login’] è impostato su true. Se questo valore non è impostato su true,
l’utente verrà indirizzato di nuovo verso la pagina login.php. Dal momento che questa
funzionalità verrà utilizzata di nuovo, si consiglia di inserire questa verifica all’interno di
un file delle inclusioni:
Esempio 7.30. security.inc.php
<?php
include_once ‘../common.inc.php’;
if (@$_SESSION[‘login’] !== true) {
header(‘location: login.php’);
$_SESSION[‘error’] = ‘You must log in before you can access
administration pages.’;
exit;
}
?>
[4] http://www.php.net/crypt
185
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 186
Capitolo 7: Elaborazione di dati XML con PHP
Disabilitazione della protezione per la configurazione
iniziale
Quando si configura il sito per la prima volta, è possibile che non siano stati ancora
creati degli amministratori. Ci si chiede dunque come fare ad aggiungere amministratori se non è possibile eseguire l’accesso. Per aggiungere i primi account amministratore, è necessario disabilitare la protezione: a tale scopo, annullare i commenti
del contenuto del file security.inc.php, in modo che il file non possa eseguire alcuna
azione. Successivamente, è necessario abilitare la visualizzazione libera delle pagine
di amministrazione e aggiungere uno o due amministratori. Dopo di che, è possibile abilitare di nuovo la protezione e collegarsi utilizzando uno degli account
appena creati.
In ultimo, occorre creare una pagina di logout a cui collegarsi in modo che gli utenti possano scollegarsi e uscire dal sito prima di abbandonare la propria postazione:
Esempio 7.31. logout.php
<?php
include_once ‘../common.inc.php’;
$_SESSION[‘login’] = false;
header(‘location: index.php’);
?>
Pagina dell’indice amministrativo
La prima pagina dello strumento di amministrazione fornisce accesso a tutte le funzionalità e all’intero contenuto del sito, compresi gli utenti amministrativi, gli articoli, i news
item e altri tipi di contenuto.
Il codice per questa pagina è molto conciso. È necessario fornire collegamenti a ciascuna
delle principali parti dello strumento di amministrazione.
Esempio 7.32. index.php
<?php
include ‘security.inc.php’;
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type”
content=”text/html; charset=iso-8859-1” />
<title>Welcome to the Admin Index Page</title>
<link rel=”stylesheet” type=”text/css” href=”../xmlcms.css” />
186
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 187
Utilizzo degli articoli
</head>
<body>
<h1>Welcome to the Admin Index Page</h1>
<p>
<a href=”articletool.php”>Manage Articles</a><br />
<a href=”newstool.php”>Manage News Items</a><br />
<a href=”admintool.php”>Manage Administrators</a>
</p>
<p><a href=”logout.php”>Log out</a></p>
</body>
</html>
Ciascuna delle aree rappresentate da questi collegamenti avrà la stessa funzionalità. Ogni
singola area consentirà agli utenti di CMS di creare, modificare ed eliminare item. Nelle
sezioni successive verranno analizzate le singole attività per la prima area: gli articoli.
Utilizzo degli articoli
L’area di amministrazione degli articoli consente agli utenti di CMS di creare nuovi articoli, modificare quelli esistenti e di eliminare articoli quando occorre. Dal momento che
gli articoli sono la parte più importante del sito, si partirà da essi per poi procedere con i
news item e gli amministratori del sito nell’Appendice B, Strumento di amministrazione
di CMS.
Per la pagina principale dell’area di amministrazione degli articoli, sarà necessario un
elenco di tutti gli articoli presenti sul sito. Poiché si suppone di aver acquisito sufficiente
dimestichezza con il codice PHP, questa operazione non dovrebbe risultare troppo complicata:
Esempio 7.33. articletool.php
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type”
content=”text/html; charset=iso-8859-1” />
<title>Article Index</title>
<link rel=”stylesheet” type=”text/css” href=”../xmlcms.css” />
</head>
<body>
<h1>Article Index</h1>
187
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 188
Capitolo 7: Elaborazione di dati XML con PHP
<p><a href=”articletool_create.php”>Create New Article</a></p>
<p><a href=”index.php”>Cancel</a></p>
<ul>
<?php
$handle = opendir($fileDir);
while (($file = readdir($handle)) !== FALSE) {
if (is_dir($fileDir . $file)) continue;
if (!eregi(“^article.*\.xml$”, $file)) continue;
$articleFile = simplexml_load_file($fileDir . $file);
echo ‘<li>’ . htmlentities($articleFile->headline);
echo ‘ <a href=”articletool_edit.php?id=’ . $articleFile[‘id’] .
‘”>edit</a>’;
echo ‘ <a href=”doArticleDelete.php?id=’ . $articleFile[‘id’] .
‘”>delete</a></li>’;
}
?>
</ul>
</body>
</html>
Creazione di nuovi articoli
La pagina di creazione degli articoli è molto importante, in quanto consente agli amministratori del sito di creare nuovi articoli XML sul sito utilizzando un semplice form Web.
Ciascuno dei campi del form è associato a un elemento nella struttura del documento
XML pianificata nel Capitolo 1, Introduzione a XML, e modificata nel Capitolo 3, DTD
per la consistenza.
Gli articoli creati dovrebbero risultare come quello riportato di seguito:
<?xml version=”1.0” encoding=”iso-8859-1”?>
<article id=”article12499300388912”>
<authorid>1</authorid>
<categoryid>1</categoryid>
<headline>Using XML with PHP</headline>
<description>PHP offers many ways to work with XML</description>
<pubdate>2004-06-26</pubdate>
<status>live</status>
<keywords>XML PHP SAX DOM SimpleXML</keywords>
<body><![CDATA[
<h1>Using XML with PHP</h1>
<p>PHP is very powerful. It offers many ways to work with
XML.</p>
]]></body>
</article>
188
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 189
Creazione di nuovi articoli
In particolare, è bene ricordare che occorre generare un ID univoco e compilare tutte le
varie parti dei metadati.
Creare un form che contenga campi per tutte queste informazioni. Iniziare con la verifica
che permette di assicurarsi che l’utente è collegato:
Esempio 7.34. articletool_create.php (estratto)
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
?>
Iniziare ora la creazione del codice HTML, includendo un collegamento a un nuovo
foglio di stile denominato forms.css, che conterrà le regole per il layout di form di amministrazione piuttosto complessi come quello riportato di seguito:
Esempio 7.35. articletool_create.php (estratto)
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type”
content=”text/html; charset=iso-8859-1” />
<title>Create a New Article</title>
<link rel=”stylesheet” type=”text/css” href=”../xmlcms.css” />
<link rel=”stylesheet” type=”text/css” href=”forms.css” />
</head>
<body>
Infine, creare il form. Il form è costituito prevalentemente da semplici campi, ma per selezionare un autore e una categoria occorrono elenchi dinamici che verranno estratti dai
file appropriati utilizzando SimpleXML.
Esempio 7.36. articletool_create.php (estratto)
<h1>Create a New Article</h1>
<p><a href=”articletool.php”>Cancel</a></p>
<form action=”doArticleCreate.php” method=”post”>
<div class=”fields”>
<p>
<label for=”headline”>Headline</label>
<input type=”text” id=”headline” name=”headline”
class=”text” />
</p>
<p>
<label for=”author”>Author</label>
<select id=”authorid” name=”authorid”>
<?php
189
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 190
Capitolo 7: Elaborazione di dati XML con PHP
$authors = simplexml_load_file($fileDir . ‘authors.xml’);
foreach ($authors->author as $author) {
echo ‘<option value=”’ . htmlentities($author[‘id’]) .
‘”>’ . htmlentities($author->name) . ‘</option>’;
}
?>
</select>
</p>
<p>
<label for=”category”>Category</label>
<select id=”categoryid” name=”categoryid”>
<?php
$cats = simplexml_load_file($fileDir . ‘categories.xml’);
foreach ($cats->category as $cat) {
echo ‘<option value=”’ . htmlentities($cat[‘id’]) . ‘”>’ .
htmlentities($cat[‘label’]) . ‘</option>’;
}
?>
</select>
</p>
<p>
<label for=”status”>Status</label>
<select id=”status” name=”status”>
<option value=”in progress”>In Progress</option>
<option value=”live”>Live</option>
</select>
</p>
<p>
<label for=”keywords”>Keywords</label>
<input type=”text” id=”keywords” name=”keywords” class=”text”
/>
</p>
<p>
<label for=”description”>Description</label>
<textarea id=”description” name=”description”></textarea>
</p>
<p>
<label for=”body”>Article Body (HTML)</label>
<textarea id=”body” name=”body”></textarea>
</p>
</div>
<div class=”actions”>
<input type=”submit” value=”Add Article” />
<input type=”reset” value=”Reset” />
</div>
</form>
</body>
</html>
190
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 191
Creazione di nuovi articoli
Di seguito viene riportato il codice del foglio di stile che esegue il layout di questo complesso form:
Esempio 7.37. forms.css
form .actions {
text-align: center;
}
form p {
clear: left;
margin: 1px 0;
}
form label {
float: left;
width: 15%;
padding-right: 10px;
text-align: right;
}
input.text, input.password, select {
width: 300px;
}
textarea {
width: 70%;
height: 4em;
}
textarea#body {
height: 30em;
}
L’action del form è impostata sulla pagina doArticleCreate.php, che utilizza funzioni
DOM per creare un articolo XML dalle informazioni contenute nel form. Dal momento
che si tratta di un passaggio molto complesso, il codice verrà riportato e analizzato a
blocchi.
La prima parte del file è l’inizio del nuovo documento XML, in cui viene impostata la versione e creato l’elemento root, article.
Esempio 7.38. doArticleCreate.php (estratto)
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
$doc = new DOMDocument();
$root = $doc->createElement(‘article’);
$root = $doc->appendChild($root);
191
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 192
Capitolo 7: Elaborazione di dati XML con PHP
Successivamente, viene aggiunto un attributo id al nodo article. L’ID sarà composto dal
termine article seguito da un timestamp. Nel caso in cui si creino contemporaneamente
più di un articolo, ricercare un file esistente il cui nome contenga lo stesso ID e incrementare il timestamp di un’unità fino a individuare un ID che non crei conflitti.
Esempio 7.39. doArticleCreate.php (estratto)
$timestamp = date(‘YmdHis’);
do {
$id = ‘article’ . $timestamp++;
} while (file_exists($fileDir . $id . ‘.xml’));
$root->setAttribute(‘id’, $id);
Dopo aver creato l’elemento root, occorre creare, nell’ordine appropriato, i relativi elementi figlio. Il primo è authorid. Si noti che l’elemento authorid è un elemento figlio di
article e che lo stesso ID è un elemento figlio di authorid.
Esempio 7.40. doArticleCreate.php (estratto)
$author = $doc->createElement(‘authorid’);
$root->appendChild($author);
$atext = $doc->createTextNode($_POST[‘authorid’]);
$author->appendChild($atext);
Viene utilizzata la stessa tecnica illustrata sopra per generare gli elementi categoryid,
headline, description, status e keywords. Il valore di pubdate viene generato dallo script,
ma per il resto è lo stesso.
Esempio 7.41. doArticleCreate.php (estratto)
$cat = $doc->createElement(‘categoryid’);
$root->appendChild($cat);
$ctext = $doc->createTextNode($_POST[‘categoryid’]);
$cat->appendChild($ctext);
$head = $doc->createElement(‘headline’);
$root->appendChild($head);
$htext = $doc->createTextNode($_POST[‘headline’]);
$head->appendChild($htext);
$desc = $doc->createElement(‘description’);
$root->appendChild($desc);
$dtext = $doc->createTextNode($_POST[‘description’]);
$desc->appendChild($dtext);
$pub = $doc->createElement(‘pubdate’);
$root->appendChild($pub);
$pubtext = $doc->createTextNode(date(‘Y-m-d’));
$pub->appendChild($pubtext);
192
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 193
Creazione di nuovi articoli
$stat = $doc->createElement(‘status’);
$root->appendChild($stat);
$stext = $doc->createTextNode($_POST[‘status’]);
$stat->appendChild($stext);
$key = $doc->createElement(‘keywords’);
$root->appendChild($key);
$ktext = $doc->createTextNode($_POST[‘keywords’]);
$key->appendChild($ktext);
Successivamente, viene elaborato il testo del corpo. È bene ricordare che tali informazioni
dovranno essere archiviate come HTML, il che significa che conterranno numerosi tag.
Se si utilizza DOM per emettere questo valore come testo, il file XML risultante sarà difficile da leggere, con entità di caratteri quali &lt; e &gt; sparse in tutto il file.
Come già menzionato nel Capitolo 1, Introduzione a XML, per garantire la leggibilità del
codice, occorre memorizzare il testo del corpo come sezione CDATA all’interno del file
XML, in modo che i caratteri speciali non debbano essere convertiti in entità di caratteri.
Anziché utilizzare createTextNode, verrà utilizzato createCDATASection. Il testo HTML del
form verrà inserito all’interno di questo comando.
Esempio 7.42. doArticleCreate.php (estratto)
$body = $doc->createElement(‘body’);
$root->appendChild($body);
$cdata = $doc->createCDATASection($_POST[‘body’]);
$body->appendChild($cdata);
Successivamente, scrivere l’intera struttura ad albero XML in un file, utilizzando l’ID
generato precedentemente con un nome file:
Esempio 7.43. doArticleCreate.php (estratto)
$filename = $fileDir . $id . ‘.xml’;
$doc->save($filename);
Infine, occorre reindirizzare l’utente verso la pagina articletool.php, dove il file appena
creato dovrebbe essere contenuto nell’elenco degli articoli principale.
Esempio 7.44. doArticleCreate.php (estratto)
header(‘location: articletool.php’);
193
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 194
Capitolo 7: Elaborazione di dati XML con PHP
Modifica di un articolo XML
In genere, la modifica di un articolo XML è pressoché uguale alla creazione di un articolo,
ad eccezione del fatto che occorre caricare i valori di un articolo esistente nel form e scrivere le modifiche apportate all’esterno del file.
Come prima cosa, creare il codice per la pagina del form. La prima parte dovrebbe risultare ora familiare: infatti, verifica che l’utente sia collegato.
Esempio 7.45. articletool_edit.php (estratto)
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
Successivamente, occorre aprire il file per ricercare il documento che l’utente desidera
modificare. Poiché per ora non verranno apportate modifiche al file, è possibile utilizzare
SimpleXML per aprire il file ed estrarre le informazioni necessarie.
Esempio 7.46. articletool_edit.php (estratto)
if (!isset($_GET[‘id’]) || $_GET[‘id’] == ‘’ ||
!file_exists($fileDir . $_GET[‘id’] . ‘.xml’)) {
header(‘location: articletool.php’);
exit;
}
$file = simplexml_load_file($fileDir . $_GET[‘id’] . ‘.xml’);
?>
Si dispone ora semplicemente della markup per un form molto simile a quello di articletool_create.php, ad eccezione del fatto che questa volta il valore esistente per ciascun
file verrà richiamato dalla variabile $file.
Esempio 7.47. articletool_edit.php (estratto)
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type”
content=”text/html; charset=iso-8859-1” />
<title>Edit Article</title>
<link rel=”stylesheet” type=”text/css” href=”../xmlcms.css” />
<link rel=”stylesheet” type=”text/css” href=”forms.css” />
</head>
<body>
<h1>Edit Article</h1>
<p><a href=”articletool.php”>Cancel</a></p>
<form action=”doArticleUpdate.php” method=”post”>
<input type=”hidden” name=”id”
value=”<?php echo htmlentities($_GET[‘id’]); ?>” />
194
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 195
Modifica di un articolo XML
<div class=”fields”>
<p>
<label for=”headline”>Headline</label>
<input type=”text” id=”headline” name=”headline” class=”text”
value=”<?php echo htmlentities($file->headline); ?>” />
</p>
<p>
<label for=”author”>Author</label>
<select id=”authorid” name=”authorid”>
<?php
$authors = simplexml_load_file($fileDir . ‘authors.xml’);
foreach ($authors->author as $author) {
if ((string)$author[‘id’] == (string)$file->authorid) {
echo ‘<option value=”’ . htmlentities($author[‘id’]) .
‘” selected=”selected”>’ .
htmlentities($author->name) . ‘</option>’;
} else {
echo ‘<option value=”’ . htmlentities($author[‘id’]) .
‘”>’ . htmlentities($author->name) . ‘</option>’;
}
}
?>
</select>
</p>
<p>
<label for=”category”>Category</label>
<select id=”categoryid” name=”categoryid”>
<?php
$cats = simplexml_load_file($fileDir . ‘categories.xml’);
foreach ($cats->category as $cat) {
if ((string)$cat[‘id’] == (string)$file->categoryid) {
echo ‘<option value=”’ . htmlentities($cat[‘id’]) .
‘” selected=”selected”>’ .
htmlentities($cat[‘label’]) . ‘</option>’;
} else {
echo ‘<option value=”’ . htmlentities($cat[‘id’]) .
‘”>’ . htmlentities($cat[‘label’]) . ‘</option>’;
}
}
?>
</select>
</p>
<p>
<label for=”status”>Status</label>
<select id=”status” name=”status”>
<option value=”in progress”
<?php if ((string)$file->status == ‘in progress’)
echo ‘selected=”selected”’?>>In Progress</option>
195
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 196
Capitolo 7: Elaborazione di dati XML con PHP
<option value=”live”
<?php if ((string)$file->status == ‘live’)
echo ‘selected=”selected”’?>>Live</option>
</select>
</p>
<p>
<label for=”keywords”>Keywords</label>
<input type=”text” id=”keywords” name=”keywords” class=”text”
value=”<?php echo htmlentities($file->keywords); ?>” />
</p>
<p>
<label for=”description”>Description</label>
<textarea id=”description” name=”description”>
<?php echo htmlentities($file->description); ?></textarea>
</p>
<p>
<label for=”body”>Article Body (HTML)</label>
<textarea id=”body” name=”body”>
<?php echo htmlentities($file->body); ?></textarea>
</p>
</div>
<div class=”actions”>
<input type=”submit” value=”Update Article” />
<input type=”reset” value=”Reset” />
</div>
</form>
</body>
</html>
Il file doArticleUpdate.php che elabora questo form è molto simile allo script
doArticleCreate.php:
Esempio 7.48. doArticleUpdate.php
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
$doc = new DOMDocument();
$root = $doc->createElement(‘article’);
$root = $doc->appendChild($root);
$id = $_POST[‘id’];
$root->setAttribute(‘id’, $id);
…
$filename = $fileDir . $id . ‘.xml’;
unlink($filename);
196
PHP_CAP07.qxd
19/05/2006
11.14
Pagina 197
Eliminazione di un articolo XML
$doc->save($filename);
header(‘location: articletool.php’);
?>
Eliminazione di un articolo XML
Eliminare un file XML è un’operazione molto semplice. Quando si passa un ID alla
pagina doArticleDelete.php, il file corrispondente viene eliminato e l’utente viene riportato alla pagina articletool.php:
Esempio 7.49. doArticleDelete.php
<?php
include ‘security.inc.php’;
include_once ‘../common.inc.php’;
$filename = $fileDir . $_GET[‘id’] . ‘.xml’;
unlink($filename);
header(‘location: articletool.php’);
?>
A questo punto, si dispone di una pagina di accesso, di un indice amministrativo, nonché
di pagine in cui è possibile aggiungere, modificare ed eliminare gli articoli. Come già anticipato nel corso di questo capitolo, le altre pagine di amministrazione verranno descritte
nell’Appendice B, Strumento di amministrazione di CMS. Come sarà possibile notare, il
codice scritto per la creazione di queste prime pagine verrà utilizzato di nuovo per completare la realizzazione dello strumento di amministrazione.
Riepilogo
In questo capitolo è stato illustrato l’utilizzo delle funzionalità SAX, DOM e SimpleXML
in PHP. A questo punto, le informazioni acquisite finora sono sufficienti per gestire la
maggior parte delle attività di elaborazione XML. La seconda parte di questo capitolo è
stata dedicata alla creazione di form amministrativi necessari per gestire gli articoli del
sito Web.
Nel capitolo successivo verranno descritti i due standard RSS e RDF, generalmente utilizzati per la creazione di intestazioni e altri feed di informazioni disponibili per terze parti
nel formato XML.
197