Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

SimpleXML: gestire XML in PHP 5

La libreria SimpleXML permette di leggere e filtrare documenti XML: un esempio con un feed RSS
La libreria SimpleXML permette di leggere e filtrare documenti XML: un esempio con un feed RSS
Link copiato negli appunti

Le librerie che possiamo considerare standard che permettono l'accesso in
lettura, modifica ed eventualmente interrogazione di file XML sono
fondamentalmente DOM e SAX. PHP fornisce un'implementazione di entrambe
le librerie, anche se a partire dalla versione 5 espone un sistema molto
più semplice e diretto per accedere ai file XML: la libreria SimpleXML
abilitata di default all'interno del motore PHP.

La libreria in questione ha il grosso vantaggio di avere
un'interfaccia ad oggetti
molto semplice ed intuitiva, che, a
differenza del più prolisso DOM, richiede pochissime righe di codice per
accedere agli elementi interessati e mantiene intatta la struttura del
file XML anche nella sua rappresentazione interna (a differenza di SAX
che ci obbliga a tener traccia manualmente delle gerarchie durante la
gestione degli eventi generati). In aggiunta espone una funzione, che
vedremo alla fine dell'articolo, che permette di eseguire query XPath
sull'oggetto per recuperare nodi specifici.

Leggere file XML

Il primo esempio che andrò ad illustrare si propone di leggere un file XML
e restituire in output il valore di alcuni attributi ed il contenuto di
alcuni elementi testuali. Il file XML d'esempio sarà il seguente:

<?xml version="1.0" encoding="utf-8"?>
<articles>
    <article id="1">
        <title>Articolo numero 1</title>
        <author>Gabriele Farina</author>
    </article>
    <article id="2">
        <title>Articolo numero 2</title>
        <author>Gabriele Farina</author>
    </article>
    <article id="3">
        <title>Articolo numero 3</title>
        <author>Francesco Caccavella</author>
    </article>
</articles>

Poniamoci come obiettivo quello di estrarre un elenco di tutti gli
articoli:

<?php

$xml = simplexml_load_file('articles.xml');

echo "<h3>Articoli salvati nel file articles.xml
(".count($xml->article).")</h3>";
echo "<ul>";
foreach($xml->article as $article)
{
    echo '<li><a
href="showarticle.php?id='.$article['id'].'">'.$article->title.'</a>
<em>(di '.$article->author.')</em></li>';
}
echo "</ul>";

?>

Eseguendo lo script otteniamo un output corretto estratto con facilità dal
file XML. Utilizzando la funzione simplexml_load_file
(segnata in rosso nel codice) carichiamo all'interno di un oggetto
SimpleXML il contenuto di un file passato come argomento (in verde nel
codice). l'argomento può essere sia un file che risiede sulla macchina
locale come un file che risiede in remoto su un altro server. L'oggetto
restituito rappresenta la root del nostro documento XML: espone una
proprietà per ogni nodo figlio che può essere un array (nel caso ci
siano più figli omonimi) o un elemento singolo e permette di accedere
agli attributi utilizzando la sintassi che normalmente viene utilizzata
per accedere ad elementi specifici di un array.

In questo modo l'iterazione è veramente semplice: per ottenere lo stesso
risultato usando DOM o SAX avremmo dovuto operare con script più
intricati o più lunghi da scrivere. Tutta questa semplicità va a
discapito di un po' di funzionalità
che, al momento, non sono
contemplate all'interno della libreria SimpleXML: i commenti e le
processing instructions sono saltate e non vengono salvate durante il
parsing del documento. Dato che comunque SimpleXML si propone come una
libreria per gestire in modo semplice documenti XML semplici, queste non
sono mancanze che attualmente complicano il modo di operare.

Interrogare gli elementi con XPath

Una delle funzionalità più interessanti di SimpleXML è la possibilità di
interrogare l'oggetto restituito dalle funzioni simplexml_load_*
con query XPath di complessità anche elevata.
XPath
è un linguaggio standard creato dal W3C che viene utilizzato
per interrogare documenti XML alla ricerca di elementi che rispondono a
determinati criteri. Un'istruzione XPath è composta da un'unica
espressione gerarchica che, applicata ad un documento XML, estrae
solamente i nodi che rispondono alle richieste effettuate. Vediamo
qualche esempio applicato al seguente documento XML:

<?xml version="1.0" encoding="utf-8"?>
<articles>
    <article id="1">
        <title>Articolo numero
1</title>
        <author>Gabriele
Farina</author>
        <date>2006-05-10</date>
    </article>
    <article id="2">
        <title>Articolo numero
2</title>
        <author>Francesco
Caccavella</author>
        <date>2006-04-11</date>
    </article>
</articles>

Vogliamo accedere all'articolo con id 1:

/articles/article[@id=1]
//article[@id=1]

Vogliamo accedere a tutti gli articoli stampati in un anno o mese
specifico:

//article[starts-with(date, "2006")]
//article[starts-with(date, "2006-05")]

Vogliamo recuperare tutti gli articoli:

//article

Dopo una breve panoramica e qualche semplice esempio su XPath vediamo come
possiamo applicarlo a SimpleXML creando un semplice script
che esegua il parsing di un documento RSS 2.0 (nello
specifico quello del blog di HTML.it che si riferisce alla sezione PHP
ed opensource) e visualizzi gli ultimi post in base a determinate
condizioni. Per comodità ho deciso di utilizzare
Smarty
e il seguente template:

<html>
  <head>
    <title>Test SimpleXML Xpath</title>
  </head>
  <body>
    <h3>{$blog->title}</h3>
    <em>{$blog->description}</em> <a href="{$blog->link}">vai</a>
    
    <h4>Articoli di oggi</h4>
    <ul>
      {section loop=$today_articles name=a}
      <li>
        <a
href="{$today_articles[a]->link}">{$today_articles[a]->title}</a>
        di <em>{$today_articles[a]->author}</em>
      </li>
      {sectionelse}
      <li>Nessun articolo</li>
      {/section}
    </ul>
    
    <h4>Articoli di Gabriele Farina</h4>
    <ul>
      {section loop=$gabriele_articles name=a}
      <li>
        <a
href="{$gabriele_articles[a]->link}">{$gabriele_articles[a]->title}</a>
        del <em>{$gabriele_articles[a]->pubDate}</em>
      </li>
      {sectionelse}
      <li>Nessun articolo</li>
      {/section}
    </ul>
    
    <h4>Articoli che accennano a Python</h4>
    <ul>
      {section loop=$python_articles name=a}
      <li>
        <a
href="{$python_articles[a]->link}">{$python_articles[a]->title}</a>
        di <em>{$python_articles[a]->author}</em>
      </li>
      {sectionelse}
      <li>Nessun articolo</li>
      {/section}
    </ul>
    
  </body>
</html>

Il codice PHP per riempire il template:

<?php

require_once 'smarty/Smarty.class.php';

$tpl = new Smarty;
$xml =
simplexml_load_file('http://blog.html.it/archivi/php_e_open_source.xml');

$channel = $xml->xpath('//channel');
$tpl->assign('blog', $channel[0]);

$items = $xml->xpath('//item[starts-with(pubDate, "'.date('D, d M
Y').'")]');
$tpl->assign('today_articles', $items);

$items = $xml->xpath('//item[starts-with(author, "g.farina@html.it")]');
$tpl->assign('gabriele_articles', $items);

$items = $xml->xpath('//item[contains(description, "Python")]');
$tpl->assign('python_articles', $items);

$tpl->display('sxml.tpl');

?>

A parte l'inclusione della libreria smarty, segnata in
rosso, il resto dello script è veramente semplice: difatti basta
utilizzare il metodo XPath dell'oggetto SimpleXML per ottenere una lista
di nodi che rispondono a determinate caratteristiche. Questi nodi poi
possono essere gestiti nello stesso identico modo in cui vengono gestiti
dei nodi SimpleXML, usando le proprietà per accedere ai figli e la
sintassi degli array per accedere agli attributi.

Il problema dei namespace

Per essere semplice SimpleXML non tiene conto (in apparenza) dei namespace
quando esegue il parsing di un documento e di conseguenza risulta
praticamente impossibile accedere a determinati elementi attraverso
XPath utilizzando il namespace come discriminante. A
fronte di questo nella versione 5.1 di PHP è stato aggiunto un metodo
all'oggetto SimpleXML che permette di associare un alias ad un
determinato namespace in modo che si possano effettuare query XPath
utilizzando gli alias così registrati:

<?php

$rss_1_0 = <<<RDF
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://purl.org/rss/1.0/"
>
<channel rdf:about="http://html.it/">
    <title>HTML.it</title>
    <link>https://www.html.it/</link>
    <description>Il portale italiano dello sviluppo su
web</description>
</channel>

<item rdf:about="http://php.html.it">
    <title>Log delle informazioni in PHP</title>
   
<link>http://php.html.it/articoli/leggi/1747/log-delle-informazioni-in-php/</link>
    <description>Modulo per il logging ....</description>
    <dc:date>2006-06-22</dc:date>
</item>

</rdf:RDF>
RDF;

$s = simplexml_load_string($rss_1_0);
$s->registerXPathNamespace('rss', 'http://purl.org/rss/1.0/');
$titles = $s->xpath('//rss:item/rss:title');

foreach ($titles as $title)
{
print "$titlen";
}

?>

Come possiamo notare in questo modo viene recuperato solamente il titolo
che ha come namespace http://purl.org/rss/1.0/.
Purtroppo anche questa soluzione ha i suoi problemi: difatti, dato che
XPath non gestisce correttamente i namespace di default, non è possibile
effettuare query basandosi direttamente su questi.

Ti consigliamo anche