Leggere un File XML con PHP

leggere file xml con php Ho deciso di scrivere questo documento nel momento in cui ho cercato sulla rete documenti in italiano relativi al parsing dell’XML con PHP, senza trovarne molti. Allora ho deciso di dare il mio contributo alle persone interessate all’argomento con la stesura di questo documento. Mi sono impegnato molto per cercare di rendere la lettura comprensibile a tutti, partendo da concetti basilari e teorici, fino ad arrivare ad esempi pratici commentati.


Cos’è l’XML

L’ Extensible Markup Language (XML) è un linguaggio di marcatura simile all’HTML progettato per l’interscambio di documenti strutturati sul web. Infatti, con gli strumenti e la flessibilità che l’XML ci fornisce, possiamo descrivere e fornire una struttura razionale e trasportabile sotto ogni tipo di piattaforma ai dati all’interno di documenti di varie forme, adattando al meglio i dati stessi, ma soprattutto il linguaggio stesso, al tipo di informazione che desideriamo descrivere. XML è uno standard definito dal W3C. Maggiori informazioni sull’ XML sono reperibili a http://www.w3.org/XML/. Una traduzione in italiano di un articolo sull’XML edito dal W3C è disponibile a http://it.wikipedia.org/wiki/XML

.

Elaborare l’XML

Un documento XML può essere processato da uno strumento chiamato parser, un elaboratore che interpreta i dati a basso livello e costruisce una rappresentazione di questi. Dalla rappresentazione ricavata possiamo distinguere due tipologie di parser, che seguono standard diversi:

  • Simple API for XML (SAX), tipologia di parser che segue uno standard basato sugli eventi: il documento XML viene elaborato carattere per carattere dal parser, che genera un determinato evento ogni qualvolta un particolare comando viene trovato. SAX non è uno standard W3C, ma è stato sviluppato da membri della mailing list XML-DEV. Per maggiori informazioni su SAX http://www.saxproject.org/.
  • Document Object Model (DOM), tipologia di parser che segue uno standard più sofisticato e di conseguenza più dispendioso in termini di risorse di sistema, in quanto l’intero documento XML viene caricato in memoria e viene rappresentato in una struttura ad albero di oggetti-nodo, la quale può essere modificata tramite semplici chiamate API. Questa tipologia di parser segue lo standard W3C. Per maggiori informazioni su DOM http://www.w3.org/DOM/.

Simple API for XML (SAX)

Descrivere a grandi linee, con precisione e semplicemente una determinata tecnologia non è affatto semplice. La tecnologia SAX implementa cinque interfacce di programmazione, o per meglio dire API, di cui quattro, di tipo Handler, si occupano dell’operazione di parsing, e una, di tipo Reader, dell’operazione di lettura del documento XML. Ogni interfaccia gestisce le proprie operazioni o può far in modo che il programmatore le gestisca attraverso i metodi, funzioni che operano su un oggetto specifico dichiarate attraverso l’implementazione dell’interfaccia stessa. XMLReader è l’interfaccia di tipo Reader che si occupa di processare e leggere il documento. Durante la lettura del documento XML, il parser SAX è in grado di rilevare alcuni eventi, che corrispondono alla lettura di un elemento tipo l’apertura e la chiusura di un documento XML o l’apertura e la chiusura di un tag. ContentHandler è l’interfaccia che associa, ad ogni metodo implementato, un evento, lanciato in seguito alla lettura di un elemento. In pratica, i metodi implementati dall’interfaccia ContentHandler, forniscono al parser segnali o notifiche sul contenuto logico del documento, necessari al fine del rilevamento degli eventi. Attraverso quest’interfaccia, possiamo personalizzare la gestione dei tag durante il processo di parsing, decidendo cosa fare quando il reader incontra i tag del documento XML, associando agli eventi prima citati delle funzioni da noi definite, chiamate funzioni di callback. Per far ciò dobbiamo registrare queste funzioni attraverso altre funzioni di registrazione predefinite: praticamente con questa operazione indichiamo al parser quali sono le funzioni da noi definite e a quali eventi rispettivamente corrispondono. In breve, ogni qualvolta viene generato uno specifico evento e richiamato il metodo associato, viene effettuata una chiamata alla funzione di callback da noi definita e associata all’evento stesso. In questo modo possiamo personalizzare le operazioni di parsing: possiamo decidere quali informazioni immagazzinare, quali ignorare e cosa fare esattamente quando viene incontrato un tag. All’apertura di un tag viene generato l’evento startElement. Se esiste una funzione di callback associata all’evento, essa viene richiamata. Come sopra, viene evocato l’evento startElement e richiamata la funzione di callback se presente. Gli attributi del tag vengono passati come argomento alla funzione di callback. L’evento characters viene lanciato ogni qualvolta che il parser riceve una notifica di dati carattere, come il contenuto di un tag. Anche a quest’evento può essere associata una funzione di callback che verrà richiamata se presente. Alla chiusura di un tag viene generato l’evento endElement . Anche in questo caso se è presente una funzione di callback associata all’evento verrà richiamata. Il discorso è uguale nelle successive righe del codice. Gli eventi principali sono startElement , lanciato all’avvio di un tag, characters , lanciato alla lettura del contenuto di un tag, ed endElement , lanciato alla chiusura di un tag.

Parte teorica

PHP offre il supporto del modulo expat , che permette il parsing di documenti XML. Il modulo expat permette di creare parser XML, settarne i parametri e definire gestori per i vari eventi. Le funzioni relative al parser XML expat sono ampiamente documentate nella documentazione ufficiale di PHP, alla pagina http://it.php.net/manual/it/ref.xml.php. È doveroso dire che, nel presente tutorial, per la vastità dell’argomento, non verranno trattate tutte le funzioni relative ad expat, per cui lo studio della documentazione ufficiale è caldamente consigliato.

Caso Pratico

Creiamo l’array $struct che conterrà l’intera struttura del documento XML:

$struct = array();

La funzione xml_parser_create inizializza un parser XML e restituisce un handle (riferimento o identificativo univoco) che verrà utilizzato dalle altre funzioni XML come riferimento al parser creato. L’ handle, in questo caso, verrà memorizzato nella variabile $xml_parser .

$xml_parser = xml_parser_create();

Funzioni di callback

Passiamo ora col definire le funzioni di callback .

startElement:La funzione che si applica all’evento startElement : La funzione deve obbligatoriamente prevedere che le verranno passati tre argomenti, nell’ordine che qui segue:



  • L’handle di riferimento al parser;
  • Il nome del tag che ha fatto generare l’evento;
  • L’array contenente le proprietà del tag.

Ora, ogni qualvolta che verrà evocato l’evento startElement , vengono eseguite le operazioni contenute in questa funzione. In questo caso, ogni qualvolta che verrà evocato l’evento startElement , verrà creato un array intermedio, $tag , che conterrà gli indici “name” e “attrs”, e infine verrà accodato all’array globale $struct . Praticamente con questa operazione creaiamo l’array che conterrà la rappresentazione del tag che ha generato l’evento. characters

La funzione associata all’evento characters :

function data($parser, $data)

La funzione deve obbligatoriamente prevedere che le verranno passati due argomenti:



  • L’handle di riferimento al parser;
  • I dati di testo.

Ogni qualvolta che verrà evocato l’evento characters , i dati di testo verranno inseriti nell’indice “data” dell’ultimo array presente nella struttura $struct : count($struct) restituisce il numero totale degli indici che costituiscono l’array $struct , e, dato che l’indicizzazione inizia da 0, l’indice dell’ultimo array equivale al numero effettivo degli indici stessi meno uno. Quindi, con questa operazione, inseriamo i dati di testo, contenuti nell’indice “data”, nell’array creato precendentemente con la funzione startElement() , che è appunto l’ultimo array presente in $struct . Una precisazione a questo punto è dovuta: l’evento characters viene evocato ogni qualvolta che il parser riceve una notifica di dati carattere. Quindi, dobbiamo prevedere che l’evento characters ci passi dati che a noi non interessa memorizzare, che possono provocare errori nella visualizzazione della struttura del documento. Il modo migliore e più elegante per ovviare a questo inconveniente è quello di utilizzare la funzione trim , che serve a tutt’altro dello scopo per cui ora la utilizziamo, ma in questo caso si rivela utilissima: se la stringa contiene dati nulli, o solo spazi vuoti, restituisce false, e l’istruzione che memorizza i dati nella struttura, contenuta all’interno del ciclo if , non verrà eseguita. endElement

La funzione associata all’evento endElement :

function endElement($parser, $name)

La funzione deve obbligatoriamente prevedere che le verranno passati due argomenti:

  • L’handle di riferimento al parser;
  • Il nome del tag che ha fatto generare l’evento.

Ogni qualvolta che verrà generato l’evento endElement , l’ultimo array creato verrà inserito nell’indice child del penultimo array. Questa funzione ha il compito di inserire i tags figli nell’indice child del tag ‘ padre ‘. Prendiamo in esame una struttura simile a questa: Come abbiamo già detto in precedenza, la funzione startElement() , ad ogni apertura di un tag, crea un array contenente i vari valori di quest’ultimo e lo accoda all’intera struttura $struct. Quindi, è la funzione endElement() , che si preoccupa di controllare se il tag che ha generato l’evento sia ” figlio ” di un altro tag, e di conseguenza inserirlo nell’indice child. Ma, quando la funzione endElement() sarà eseguita, startElement() avrà già compiuto il suo lavoro e l’array rappresentante il tag sarà già stato accodato nel primo albero di $struct . Quindi, bisognerebbe copiarne il valore nell’indice child dell’array del tag ” padre “, ed infine cancellarlo dalla struttura. In pratica, se abbiamo il tag , figlio del tag , all’apertura del tag la sua rappresentazione verrà inserita nel primo albero di $struct . Alla chiusura del tag , l’indice dell’array rappresentante il tag , che in questo caso rappresenta il tag ” padre “, corrisponderà obbligatoriamente al numero effettivo degli indici presenti nell’array $struct meno due, o in altre parole al penultimo array creato. È importante precisare, però, che questa regola generale vale soltanto se i tag figli non abbiano a loro volta dei figli: il discorso in quel caso si complica ulteriormente. Ora non ci resta, dunque, che inserire l’intera struttura dell’ultimo array nell’indice child del penultimo array, ed infine eliminare l’ultimo array con la funzione array_pop .

Registrazione delle funzioni di callback

Dopo aver definito le funzioni di callback, è necessario registrarle ed associarle ai rispettivi eventi: praticamente con questa operazione indichiamo al parser quali sono le funzioni di callback e a quali eventi corrispondono.

  • xml_set_element_handler($xml_parser, “startElement”, “endElement”);
  • xml_set_character_data_handler($xml_parser, “data”);

La funzione xml_set_element_handler ha il compito di registrare le funzioni di callback associate agli eventi startElement ed endElement . La funzione deve accettare tre parametri:

  • L’handle di riferimento al parser;
  • I l nome della funzione di callback che abbiamo creato e vogliamo associare all’evento startElement ;
  • Il nome della funzione di callback che abbiamo creato e vogliamo associare all’evento endElement .

La funzione xml_set_character_data_handler ha il compito di registrare la funzione di callback associata all’evento characters . La funzione deve accettare due parametri:

  • L’handle di riferimento al parser;
  • Il nome della funzione di callback che abbiamo creato e vogliamo associare all’evento characters .

Codice di Esempio

Dopo la spiegazione in dettaglio ecco per voi da soulbit.org un parser generico xml

<?php

$struct = array();

$xml_parser = xml_parser_create();

function startElement($parser, $name, $attrs)

{

global $struct;

$tag = array(”name”=>$name,”attrs”=>$attrs);

array_push($struct,$tag);

}


function data($parser, $data) {

global $struct,$i;

if(trim($data)) {

$struct[count($struct)-1]['data']=$data; }

}


function endElement($parser, $name) {

global $struct;

$struct[count($struct)-2]['child'][] = $struct[count($struct)-1]; array_pop($struct);

}


function parse_file($file) {

global $struct;

$xml_parser = xml_parser_create();

xml_set_element_handler($xml_parser, “startElement”, “endElement”);

xml_set_character_data_handler($xml_parser, “data”);

$parse = xml_parse($xml_parser,file_get_contents($file));

if(!$parse) {

die(”XML parsing error”);

xml_parser_free($xml_parser);

}

return $struct;

}

?>



In questa configurazione il file fa da libreria e la dovete chiamare con require all’interno dello script di vostro interesse tramite la funzione parse_file(”nome_file.xml”); come potete vedere tale operazione restituisce l’array $struct, che potete navigare come volete, Se volete metterlo a secco in uno script dovrete cancellare la funzione parse_file e metterci:


$file = “example.xml”;

$parse = xml_parse($xml_parser,file_get_contents($file));

if(!$parse) { die(”XML parsing error”);

}

xml_parser_free($xml_parser);



Considerazioni finali sul parser xml

Con questo parser potrete fare molte cose interessanti come leggere e manipolare feed direttamente sul vostro sito, oppure in mancanza di un database usarlo come foglio di salvataggio, molto più potente di un semplice file di testo…oppure, il codice lo avete sbizzarritevi come volete, fatemi sapere se ci dovessero essere problemi…ciaooo

pdf

No related posts.

Articoli correlati elaborati dal plugin Yet Another Related Posts.

Tags: , , ,

Scritto da Santarelli Luca mercoledì, 28th gennaio , 2009 18:15 Letture:

    « Concatenazione delle chiamate delle funzioni membro in C++  |  Come Connettersi a Mysql con le Servlet Java, Database e JDBC »

    Leave a Reply