CXXXV. Funzioni relative al parser XML

Introduzione

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.

Requisiti

Questa estensione utilizza il modulo 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/.

Installazione

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.

Configurazione di Runtime

Questa estensione non definisce alcuna direttiva di configurazione in php.ini

Tipi di risorse

xml

La risorsa xml restituita da xml_parser_create() e xml_parser_create_ns() è un riferimento all'istanza del parser da utilizzarsi con le funzioni previste da questo modulo.

Costanti predefinite

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)

Gestori di eventi

I gestori di eventi XML definiti sono:

Tabella 1. Gestori XML supportati

Funzione PHP per attivare il gestoreDescrizione 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.

Case Folding

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().

Codici di errore

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

Codifica dei caratteri

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.

Esempi

Di seguito verranno illustrati alcuni esempi di script PHP per il parsing di documenti XML.

Esempio della struttura degli elementi 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 di mappatura dei tag XML

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);
?>

Esempio di entità XML esterna

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
"&lt;<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
"&gt;";
}

function
endElement($parser, $name)
{
    echo
"&lt;/<font color=\"#0000cc\">$name</font>&gt;";
}

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>

Sommario
utf8_decode --  Converte una stringa con caratteri ISO-8859-1 codificati con UTF-8 in formato ISO-8859-1 singolo byte
utf8_encode -- Codifica una stringa da ISO-8859-1 a UTF-8
xml_error_string -- Restituisce la stringa di errore dal parser XML
xml_get_current_byte_index -- Restituisce il corrente indice di posizione per un parser XML
xml_get_current_column_number --  Restituisce il numero di colonna corrente di un parser XML
xml_get_current_line_number -- Restituisce il numero di linea corrente da un parser XML
xml_get_error_code -- Restituisce il codice di errore dal parser XML
xml_parse_into_struct -- Analisi di dati XML in una struttura a matrice
xml_parse -- Inizia il parsing di un documento XML
xml_parser_create_ns --  Crea un parser XML con il supporto dello spazio dei nomi
xml_parser_create -- Crea un parser XML
xml_parser_free -- Cancella un parser XML
xml_parser_get_option -- Restituisce le opzioni da un parser XML
xml_parser_set_option -- Valorizza un'opzione di un parser XML
xml_set_character_data_handler -- Valorizza il gestore dei dati
xml_set_default_handler -- Valorizza il gestore di default
xml_set_element_handler -- Valorizza i gestori di inizio e fine elemento
xml_set_end_namespace_decl_handler --  Valorizza il gestore dello spazio dei nomi
xml_set_external_entity_ref_handler -- Valorizza il gestore dei riferimenti a entità esterne
xml_set_notation_decl_handler -- Valorizza il gestore delle dichiarazione delle notazioni
xml_set_object -- Utilizza il parser XML all'interno di un oggetto
xml_set_processing_instruction_handler --  Indica il gestore delle istruzioni di processo (PI)
xml_set_start_namespace_decl_handler --  Valorizza il gestore dei caratteri di dati
xml_set_unparsed_entity_decl_handler --  Valorizza il gestore delle dichiarazioni di entità non analizzate

Hosting by: hurra.com
Generated: 2007-01-26 17:56:53