haschildren()
Scopri come hasChildren() di PHP verifica se l'elemento XML corrente ha nodi figli, con esempi eseguibili e insidie comuni.
Cosa fa hasChildren()
hasChildren() è un metodo della classe SimpleXMLIterator. Restituisce true quando l'elemento su cui l'iteratore è attualmente posizionato ha almeno un elemento figlio, e false quando quell'elemento è un nodo foglia (solo testo o vuoto).
Proviene dall'interfaccia RecursiveIterator di PHP, implementata sia da SimpleXMLIterator che da SimpleXMLElement. Il suo compito è comunicare al motore di attraversamento ricorsivo: "devo scendere in questo nodo?" Questa è l'idea chiave, e la fonte della maggior parte della confusione:
hasChildren() non chiede "ha figli $this?" Chiede "l'elemento alla posizione corrente dell'iteratore ha figli?" Di solito lo si chiama mentre si itera con rewind() / valid() / next(), oppure si lascia che un RecursiveIteratorIterator lo chiami per te — non direttamente su un elemento arbitrario.
public SimpleXMLIterator::hasChildren(): boolIl metodo non accetta parametri e restituisce un bool. Per leggere i figli quando restituisce true, abbinalo a getChildren().
Configurare un SimpleXMLIterator
hasChildren() esiste solo su SimpleXMLIterator, quindi creane uno dalla tua stringa XML con new SimpleXMLIterator(), oppure carica un documento e convertilo. Ecco un piccolo catalogo in cui un elemento ha figli e uno no:
<?php
$xml = new SimpleXMLIterator(<<<XML
<store>
<book>
<title>Modern PHP</title>
<author>Josh Lockhart</author>
</book>
<note>Closed on holidays</note>
</store>
XML);
for ($xml->rewind(); $xml->valid(); $xml->next()) {
if ($xml->hasChildren()) {
echo $xml->key() . " has children:\n";
foreach ($xml->getChildren() as $name => $value) {
echo " {$name}: {$value}\n";
}
} else {
echo $xml->key() . " (leaf): " . $xml->current() . "\n";
}
}Output:
book has children:
title: Modern PHP
author: Josh Lockhart
note (leaf): Closed on holidaysNota che il ciclo scorre l'iteratore manualmente con rewind(), valid(), next(), key() e current(). hasChildren() riporta il risultato per qualsiasi elemento su cui il cursore si trova in quel momento.
Percorrere l'intero albero in modo ricorsivo
Il vero vantaggio di hasChildren() emerge quando si passa l'iteratore a un RecursiveIteratorIterator. Quel wrapper chiama hasChildren() e getChildren() per te, discendendo automaticamente così puoi appiattire un documento annidato di qualsiasi profondità:
<?php
$xml = new SimpleXMLIterator(<<<XML
<library>
<shelf>
<book>
<title>PHP Basics</title>
</book>
</shelf>
<desk>Front entrance</desk>
</library>
XML);
$tree = new RecursiveIteratorIterator(
$xml,
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($tree as $name => $node) {
echo str_repeat(' ', $tree->getDepth()) . $name . "\n";
}Output:
shelf
book
title
deskNon è necessario chiamare hasChildren() manualmente qui — RecursiveIteratorIterator lo usa internamente per decidere quando ricorrere.
Quando usarlo
- Stai iterando una struttura XML sconosciuta e hai bisogno di sapere se scendere più in profondità prima di leggere i valori.
- Stai costruendo una vista ad albero, una breadcrumb o un elenco appiattito da XML annidato.
- Vuoi che la macchina degli iteratori di PHP (
RecursiveIteratorIterator, filtri) attraversi l'XML per te invece di scrivere cicliforeachannidati.
Se vuoi semplicemente i figli di un elemento noto, di solito non hai bisogno di hasChildren() — chiama children() su un SimpleXMLElement e verifica se il risultato è vuoto con count().
Insidie comuni
- Chiamarlo su
SimpleXMLElement. Un sempliceSimpleXMLElementcreato consimplexml_load_file()osimplexml_load_string()implementaRecursiveIterator, ma la semantica utile dihasChildren()appartiene aSimpleXMLIterator. Usa quella classe quando vuoi questo metodo. - Aspettarsi che rilevi attributi o testo.
hasChildren()guarda solo gli elementi figli. Un elemento che contiene solo testo o solo attributi restituiscefalse. - Chiamarlo prima di posizionare il cursore. Esegui sempre
rewind()(o itera) prima; il risultato riflette la posizione corrente, che è indefinita prima del primo elemento.
Conclusione
SimpleXMLIterator::hasChildren() è il guardiano dell'attraversamento ricorsivo XML: indica se l'elemento corrente dell'iteratore ha elementi figli, così il tuo codice — o un RecursiveIteratorIterator — sa quando scendere. Abbinalo a getChildren() per leggere quei figli, e ricorri a children() o alla guida più ampia su SimpleXML quando hai bisogno direttamente del contenuto di un nodo.