 |
CLXXV. Funzioni relative al parser XML
XML (eXtensible Markup Language) è un formato utilizzato per l'interscambio
di documenti strutturati sul Web. Questo è uno standard definito da
The World Wide Web consortium (W3C). Maggiori informazioni su XML e
le relative tecnologie possono essere reperite all'indirizzo http://www.w3.org/XML/.
Questo modulo del PHP offre il supporto del modulo
expat di James Clark. Questo tool
permette il parsing, ma non la validazione, di documenti XML. Sono supportati
tre tipi di codifica di caratteri,
supportati anche dal PHP:US-ASCII,
ISO-8859-1 ed UTF-8.
La codifica UTF-16 non è supportata.
Questo modulo permette di creare parser XML
e di definire dei gestori per i vari eventi
XML. Inoltre ogni singolo parser XML ha diversi parametri che possono
essere configurati in base alle varie esigenze.
Di norma questo modulo utilizza un expat compat layer.
Tuttavia si può utilizzare anche expat, che può
essere reperito all'indirizzo http://www.jclark.com/xml/expat.html. Il
Makefile fornito con expat, per default, non compila la libreria,
occorre utilizzare le seguenti istruzioni per il comando make:
libexpat.a: $(OBJS)
ar -rc $@ $(OBJS)
ranlib $@ |
Il sorgente in formato package RPM può essere reperito all'indirizzo http://sourceforge.net/projects/expat/.
Queste funzioni sono abilitate per default utilizzando le libreria expat fornita.
Si può disabilitare il supporto XML utilizzando
--disable-xml.
Se si compila il PHP come modulo per Apache 1.3.9 o versioni successive, il PHP
automaticamente utilizzerà la libreria expat di Apache.
Se non si desidera utilizzare la libreria fornita, configurare il PHP
con --with-expat-dir=DIR, dove DIR
indica la directory in cui è installato expat.
La versione per Windows di PHP
ha già compilato il supporto per questo modulo. Non occorre caricare alcun modulo
addizionale per potere utilizzare queste funzioni. Questa estensione non definisce
alcuna direttiva di configurazione in php.ini
Queste costanti sono definite da questa estensione e
sono disponibili solo se l'estensione è stata compilata
nel PHP o se è stata caricata dinamicamente a runtime.
- XML_ERROR_NONE
(integer)
- XML_ERROR_NO_MEMORY
(integer)
- XML_ERROR_SYNTAX
(integer)
- XML_ERROR_NO_ELEMENTS
(integer)
- XML_ERROR_INVALID_TOKEN
(integer)
- XML_ERROR_UNCLOSED_TOKEN
(integer)
- XML_ERROR_PARTIAL_CHAR
(integer)
- XML_ERROR_TAG_MISMATCH
(integer)
- XML_ERROR_DUPLICATE_ATTRIBUTE
(integer)
- XML_ERROR_JUNK_AFTER_DOC_ELEMENT
(integer)
- XML_ERROR_PARAM_ENTITY_REF
(integer)
- XML_ERROR_UNDEFINED_ENTITY
(integer)
- XML_ERROR_RECURSIVE_ENTITY_REF
(integer)
- XML_ERROR_ASYNC_ENTITY
(integer)
- XML_ERROR_BAD_CHAR_REF
(integer)
- XML_ERROR_BINARY_ENTITY_REF
(integer)
- XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF
(integer)
- XML_ERROR_MISPLACED_XML_PI
(integer)
- XML_ERROR_UNKNOWN_ENCODING
(integer)
- XML_ERROR_INCORRECT_ENCODING
(integer)
- XML_ERROR_UNCLOSED_CDATA_SECTION
(integer)
- XML_ERROR_EXTERNAL_ENTITY_HANDLING
(integer)
- XML_OPTION_CASE_FOLDING
(integer)
- XML_OPTION_TARGET_ENCODING
(integer)
- XML_OPTION_SKIP_TAGSTART
(integer)
- XML_OPTION_SKIP_WHITE
(integer)
I gestori di eventi XML definiti sono:
Tabella 1. Gestori XML supportati Funzione PHP per attivare il gestore | Descrizione dell'evento |
---|
xml_set_element_handler() |
L'evento 'Elemento' viene attivato quando il parser XML
incontra i tag di apertura e chiusura. Esistono gestori separati
per i tag di apertura e di chiusura.
|
xml_set_character_data_handler()
|
Sono dati tutti i contenuti dei documenti XML che non siano
dei markup, compresi gli spazi tra i tag. Si noti che
il parser XML non aggiunge ne rimuove spazi, è compito
dell'applicazione decidere se gli spazi siano
significativi o meno.
|
xml_set_processing_instruction_handler()
|
Ai programmatori PHP dovrebbe già essere familiare le istruzioni di processo
(PIs). <?php ?> è un istruzione di
processo dove php viene definito
"PI target". La gestione di questi è specifica dell'applicazione,
tranne che tutti i PI targets che iniziano con "XML",
questi sono riservati.
| xml_set_default_handler() |
Tutto ciò che non rientra negli altri gestori ricade nel gestore
di default. In questo gestore si ha elementi come
la dichiarazione dei tipo documento.
|
xml_set_unparsed_entity_decl_handler()
|
Questo gestore viene richiamato per la gestione di entità non analizzate
(NDATA).
|
xml_set_notation_decl_handler()
|
Questo gestore viene richiamato per la dichiarazione di una notazione.
|
xml_set_external_entity_ref_handler()
|
Questo gestore viene richiamato quando il parser XML incontra un
riferimento ad una entità esterna analizzata.
Questa può essere, ad esempio, un riferimento ad un file o ad un URL.
Vedere esempio di entità
esterne per una dimostrazione.
|
Le funzioni di gestione degli elementi possono ottenere i nomi dei propri elementi
case-folded. Lo standard XML definisce il case-folding
come "un processo applicato ad una sequenza di caratteri,
nel quale quelli identificati come non-maiuscoli sono sostituiti
dai corrispettivi caratteri maiuscoli". In altre parole, in XML
il termine case-folding indica, semplicemente, la conversione a lettere maiuscole.
Per default, i nomi di tutti gli elementi passati alle funzioni di
gestione sono case-folded. Questo comportamento può essere verificato e
controllato nel parser XML
rispettivamente con le funzioni
xml_parser_get_option() e
xml_parser_set_option().
Vengono definite le seguenti costanti per i codici di errore XML
(come restituito da xml_parse()):
XML_ERROR_NONE | XML_ERROR_NO_MEMORY | XML_ERROR_SYNTAX | XML_ERROR_NO_ELEMENTS | XML_ERROR_INVALID_TOKEN | XML_ERROR_UNCLOSED_TOKEN | XML_ERROR_PARTIAL_CHAR | XML_ERROR_TAG_MISMATCH | XML_ERROR_DUPLICATE_ATTRIBUTE | XML_ERROR_JUNK_AFTER_DOC_ELEMENT | XML_ERROR_PARAM_ENTITY_REF | XML_ERROR_UNDEFINED_ENTITY | XML_ERROR_RECURSIVE_ENTITY_REF | XML_ERROR_ASYNC_ENTITY | XML_ERROR_BAD_CHAR_REF | XML_ERROR_BINARY_ENTITY_REF | XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF | XML_ERROR_MISPLACED_XML_PI | XML_ERROR_UNKNOWN_ENCODING | XML_ERROR_INCORRECT_ENCODING | XML_ERROR_UNCLOSED_CDATA_SECTION | XML_ERROR_EXTERNAL_ENTITY_HANDLING |
L'estensione XML di PHP supporta il set di caratteri
Unicode tramite
differenti codifiche di caratteri.
Esistono due tipi di codifiche di caratteri, source
encoding e target encoding.
Nella rappresentazione interna dei documenti il PHP utilizza sempre
la codifica UTF-8.
La codifica del sorgente viene eseguita quando un documento XML viene analizzato. Durante la creazione di un parser
XML, si può specificare la codifica del sorgente (questa codifica
non potrà essere variata in seguito nel corso della vita del parser XML).
Le codifiche supportate sono ISO-8859-1,
US-ASCII e UTF-8.
Le prime due sono codifiche a singolo byte, ciò significa che
ciascun carattere è rappresentato da un byte singolo,
mentre la codifica UTF-8 può rappresentare caratteri
composti da un numero variabile di bit (fino a 21) usando da uno fino
a quattro byte. La codifica del sorgente utilizzata per default dal PHP è
ISO-8859-1.
La codifica per il destinatario viene eseguita quando il PHP passa i dati alle funzioni di
gestione del XML. Quando viene creato un parser XML, la codifica
per il destinatario viene posta uguale alla codifica del sorgente, ma ciò può
essere variato. La codifica per il destinatario viene applicata ai caratteri dei dati,
ai nomi dei tag e alle istruzioni di processamento.
Se il parser XML incontra caratteri esterni al range dei caratteri
rappresentabili dalla codifica, restituirà un
errore.
Se il PHP incontra nel documento analizzato dei caratteri che non
è in grado di rappresentare con la codifica scelta per il destinatario, "degrada"
il carattere problematico. Attaualmente ciò significa sostuire il
carattere in questione con un punto interrogativo.
Di seguito verranno illustrati alcuni esempi di script PHP per il parsing di documenti XML.
Il primo esempio visualizza, con indentazione, la struttura degli
elementi di apertura di un documento.
Esempio 1. Visualizza la struttura degli elementi XML
<?php $file = "data.xml"; $depth = array();
function startElement($parser, $name, $attrs) { global $depth; for ($i = 0; $i < $depth[$parser]; $i++) { echo " "; } echo "$name\n"; $depth[$parser]++; }
function endElement($parser, $name) { global $depth; $depth[$parser]--; }
$xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "startElement", "endElement"); if (!($fp = fopen($file, "r"))) { die("could not open XML input"); }
while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser); ?>
|
|
Esempio 2. Conversione da XML a HTML
Il seguente esempio converte i tag di un documento XML in
tag HTML. Gli elementi non trovati nella matrice dei tag saranno ignorati.
Ovviamente questo esempio funziona solo con uno specifico tipo di
documento XML:
<?php $file = "data.xml"; $map_array = array( "BOLD" => "B", "EMPHASIS" => "I", "LITERAL" => "TT" );
function startElement($parser, $name, $attrs) { global $map_array; if (isset($map_array[$name])) { echo "<$map_array[$name]>"; } }
function endElement($parser, $name) { global $map_array; if (isset($map_array[$name])) { echo "</$map_array[$name]>"; } }
function characterData($parser, $data) { echo $data; }
$xml_parser = xml_parser_create(); // Si utilizza il case-folding per essere certi di trovare le tag in $map_array xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); if (!($fp = fopen($file, "r"))) { die("Non si riesce ad aprire il documento XML"); }
while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("Errore XML: %s alla linea %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser); ?>
|
|
Questo esempio evidenzia il codice XML. Si illustrerà come utilizzare
il riferimento ad entità esterne per includere ed analizzare altri
documenti, sarà illustrato anche come processare le PI, ed il modo
per determinare l'affidabilità del codice contenuto delle PI.
I documenti XML che possono essere usati per questo esempio sono
presenti dopo l'esempio (xmltest.xml e
xmltest2.xml.)
Esempio 3. Esempio di entità esterna
<?php $file = "xmltest.xml";
function trustedFile($file) { // si considera affidabili soltanto i file locali del proprio utente if (!eregi("^([a-z]+)://", $file) && fileowner($file) == getmyuid()) { return true; } return false; }
function startElement($parser, $name, $attribs) { echo "<<font color=\"#0000cc\">$name</font>"; if (sizeof($attribs)) { while (list($k, $v) = each($attribs)) { echo " <font color=\"#009900\">$k</font>=\"<font color=\"#990000\">$v</font>\""; } } echo ">"; }
function endElement($parser, $name) { echo "</<font color=\"#0000cc\">$name</font>>"; }
function characterData($parser, $data) { echo "<b>$data</b>"; }
function PIHandler($parser, $target, $data) { switch (strtolower($target)) { case "php": global $parser_file; // Se il documento analizzato è "affidabile", si può dire che è sicura // l'esecuzione del codice PHP presente in esso. In caso contrario si visualizza // il codice. if (trustedFile($parser_file[$parser])) { eval($data); } else { printf("Codice PHP inaffidabile: <i>%s</i>", htmlspecialchars($data)); } break; } }
function defaultHandler($parser, $data) { if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") { printf('<font color="#aa00aa">%s</font>', htmlspecialchars($data)); } else { printf('<font size="-1">%s</font>', htmlspecialchars($data)); } }
function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId) { if ($systemId) { if (!list($parser, $fp) = new_xml_parser($systemId)) { printf("Non si riesce ad aprire l'entità %s at %s\n", $openEntityNames, $systemId); return false; } while ($data = fread($fp, 4096)) { if (!xml_parse($parser, $data, feof($fp))) { printf("XML error: %s at line %d while parsing entity %s\n", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser), $openEntityNames); xml_parser_free($parser); return false; } } xml_parser_free($parser); return true; } return false; }
function new_xml_parser($file) { global $parser_file;
$xml_parser = xml_parser_create(); xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); xml_set_processing_instruction_handler($xml_parser, "PIHandler"); xml_set_default_handler($xml_parser, "defaultHandler"); xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler"); if (!($fp = @fopen($file, "r"))) { return false; } if (!is_array($parser_file)) { settype($parser_file, "array"); } $parser_file[$xml_parser] = $file; return array($xml_parser, $fp); }
if (!(list($xml_parser, $fp) = new_xml_parser($file))) { die("Non si riesce ad aprire il documento XML"); }
echo "<pre>"; while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("Errore XML: %s alla linea %d\n", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } echo "</pre>"; echo "parsing completato\n"; xml_parser_free($xml_parser);
?>
|
|
Esempio 4. xmltest.xml <?xml version='1.0'?>
<!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [
<!ENTITY plainEntity "FOO entity">
<!ENTITY systemEntity SYSTEM "xmltest2.xml">
]>
<chapter>
<TITLE>Title &plainEntity;</TITLE>
<para>
<informaltable>
<tgroup cols="3">
<tbody>
<row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row>
<row><entry>a2</entry><entry>c2</entry></row>
<row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row>
</tbody>
</tgroup>
</informaltable>
</para>
&systemEntity;
<section id="about">
<title>Circa questo documento</title>
<para>
<!-- questo è un commento -->
<?php echo 'Ciao! Questa è la versione di PHP '.phpversion(); ?>
</para>
</section>
</chapter> |
|
Questo file è stato richiamato da xmltest.xml:
Esempio 5. xmltest2.xml <?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY testEnt "Entità di test">
]>
<foo>
<element attrib="value"/>
&testEnt;
<?php echo "Questa è una ulteriore riga di codice PHP eseguito."; ?>
</foo> |
|
|  |