PHP XML DOM
Scopri come usare l'estensione DOM di PHP per caricare, creare, modificare, interrogare (con XPath) e salvare documenti XML, con esempi eseguibili.
A cosa serve l'estensione DOM
L'estensione DOM (Document Object Model) rappresenta un documento XML in memoria come un albero di nodi. Ogni elemento, attributo, frammento di testo e commento è un oggetto nodo che puoi leggere, spostare, aggiungere o eliminare. Poiché l'intero documento viene caricato in RAM, il DOM è lo strumento giusto quando devi modificare un XML, costruire un documento da zero o eseguire query XPath che si muovono liberamente nell'albero.
Questa pagina tratta il caricamento, la creazione, la modifica, l'interrogazione e il salvataggio di XML con DOMDocument. I compromessi rispetto alle alternative più leggere sono questi:
- Usa l'estensione SimpleXML quando ti serve soltanto leggere rapidamente un XML ben formato con poco codice.
- Usa l'XML Parser (Expat) per l'elaborazione in streaming, basata su eventi, di file molto grandi che non devono essere tenuti interamente in memoria.
- Ricorri al DOM (questa pagina) quando ti serve il pieno controllo in lettura e scrittura, oltre a XPath.
Il DOM e libxml condividono lo stesso sistema di gestione degli errori; consulta PHP libxml per gestire gli errori di parsing.
Abilitare l'estensione
L'estensione DOM è inclusa in PHP ed è abilitata di default nella maggior parte delle build (fa parte del pacchetto php-xml su Debian/Ubuntu). Puoi verificare che sia disponibile:
<?php
var_dump(extension_loaded('dom')); // bool(true)Se manca, installa il pacchetto php-xml per la tua piattaforma oppure abilita extension=dom in php.ini, quindi riavvia il web server.
Caricare un documento XML
Crea un DOMDocument e carica l'XML da una stringa con loadXML() oppure da un file con load(). Attiva prima libxml_use_internal_errors(true) in modo che un markup malformato non riempia l'output di warning: gli errori li raccogli tu stesso.
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
libxml_use_internal_errors(true);
$doc = new DOMDocument();
if (!$doc->loadXML($xml)) {
foreach (libxml_get_errors() as $error) {
echo trim($error->message) . "\n";
}
libxml_clear_errors();
exit;
}
$root = $doc->documentElement;
echo "Root element: {$root->nodeName}\n";
foreach ($root->getElementsByTagName('title') as $title) {
echo "Title: {$title->nodeValue}\n";
}Output:
Root element: books
Title: PHP for Beginners
Title: Advanced XMLgetElementsByTagName() restituisce un DOMNodeList live su cui puoi iterare direttamente con foreach: di solito è più chiaro che scorrere childNodes, che include anche i nodi di testo con gli spazi bianchi tra un elemento e l'altro.
Creare un documento XML da zero
Costruisci un documento creando nodi sul DOMDocument e aggiungendoli a un nodo genitore. Imposta formatOutput = true per ottenere da saveXML() un output indentato e leggibile.
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElement('books');
$doc->appendChild($root);
$book = $doc->createElement('book');
$book->setAttribute('id', '1');
$root->appendChild($book);
$title = $doc->createElement('title', 'PHP for Beginners');
$book->appendChild($title);
echo $doc->saveXML();Output:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1">
<title>PHP for Beginners</title>
</book>
</books>I metodi principali usati qui:
createElement($name, $value)— crea un elemento, con contenuto testuale opzionale.setAttribute($name, $value)— aggiunge o sovrascrive un attributo di un elemento.appendChild($node)— collega un nodo come ultimo figlio del suo genitore.
Attenzione: passare il testo direttamente a
createElement('title', $userInput)non esegue l'escape di&,<o>in modo affidabile. Per un testo non attendibile, aggiungi invece un nodo di testo:$el->appendChild($doc->createTextNode($userInput)), che esegue sempre l'escape dei caratteri speciali.
Modificare ed eliminare nodi
Poiché l'intero albero è in memoria, puoi cambiare il testo, aggiornare gli attributi e rimuovere elementi prima di salvare. Un modo pulito per individuare il nodo giusto è XPath (trattato nella prossima sezione), ma qui lo usiamo già in linea:
<?php
$xml = <<<XML
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
// Rename the first title
$first = $xpath->query('//book[@id="1"]/title')->item(0);
$first->nodeValue = 'PHP Essentials';
// Remove the second book
$second = $xpath->query('//book[@id="2"]')->item(0);
$second->parentNode->removeChild($second);
echo $doc->saveXML();Output:
<?xml version="1.0"?>
<books>
<book id="1"><title>PHP Essentials</title></book>
</books>Per eliminare un nodo si chiama removeChild() sul suo genitore, ed ecco perché $second->parentNode->removeChild($second) è l'idioma abituale. Assegnare un valore a nodeValue sostituisce il contenuto testuale di un elemento.
Interrogare con XPath
DOMXPath permette di selezionare i nodi con espressioni di percorso invece di percorrere manualmente l'albero: è molto più conciso dei cicli annidati.
<?php
$xml = <<<XML
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
// Every <title> anywhere in the document
foreach ($xpath->query('//title') as $node) {
echo $node->nodeValue . "\n";
}
// The title of the book whose id is "2"
$result = $xpath->query('//book[@id="2"]/title');
echo "Book 2: " . $result->item(0)->nodeValue . "\n";Output:
PHP for Beginners
Advanced XML
Book 2: Advanced XMLPattern XPath comuni:
| Espressione | Seleziona |
|---|---|
//title | Tutti gli elementi <title> a qualsiasi profondità |
/books/book | Gli elementi <book> figli diretti della radice <books> |
//book[@id="2"] | Gli elementi <book> con l'attributo id="2" |
//book/@id | I nodi attributo id di ogni <book> |
//book[1] | Il primo <book> (in XPath gli indici partono da 1) |
Salvare su file
Rendi persistente l'albero in memoria con save(), che restituisce false in caso di errore (per esempio una directory non scrivibile).
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElement('config');
$doc->appendChild($root);
$root->appendChild($doc->createElement('debug', 'false'));
if ($doc->save(__DIR__ . '/output.xml')) {
echo 'Saved successfully.';
} else {
echo 'Failed to save — check directory permissions.';
}Usa saveXML() (senza argomenti) quando vuoi ottenere l'XML come stringa: è comodo per restituirlo da un'API o stamparlo in una risposta.
Riepilogo
DOMDocumentcarica un intero documento XML in un albero di nodi modificabile.- Usa
loadXML()/load()per leggere,createElement()eappendChild()per costruire eremoveChild()per eliminare. DOMXPath::query()seleziona i nodi con espressioni di percorso concise.save()scrive su file;saveXML()restituisce il documento come stringa.- Scegli il DOM quando devi scrivere o interrogare XML; scegli SimpleXML per letture rapide e l'XML Parser per lo streaming di file enormi.