65 Stimmen

php SimpleXML prüft, ob ein Kind existiert

A->b->c existieren könnte, aber c möglicherweise nicht existiert. Wie kann ich das überprüfen?

1 Stimmen

Bitte wählen Sie eine neue Antwort

133voto

null Punkte 7142

Es wäre vielleicht besser, dies in eine isset()

if(isset($A->b->c)) { // c exists

Auf diese Weise können $A o $A->b gibt es nicht... es explodiert nicht.

14 Stimmen

Dies schien sauberer zu sein als die anderen Antworten, aber tatsächlich gibt SimpleXMLElement ein leeres SimpleXMLElement-Objekt für jeden angeforderten Knoten zurück, der nicht existiert. Die Methode empty() scheint also der beste Weg zu sein.

0 Stimmen

Auch, c kann fakultativ sein, aber A y b können erforderlich sein, so dass ich eine Ausnahme erhalten möchte, wenn sie nicht definiert sind - eine einfache Möglichkeit, die Integrität des Dokuments zu überprüfen

0 Stimmen

@spikyjt isset() ist die beste Route, um zu prüfen, ob der Knoten existiert. Sie können verwenden empty() wenn Sie prüfen müssen, ob der Knoten existiert UND etwas in ihm enthalten ist, d. h. zwischen > y < (entweder Text oder Unterknoten). Wenn Sie nur das Vorhandensein des Knotens prüfen wollen, dann empty() nicht ausreicht. Zum Beispiel, empty() wird dich zurückbringen true für diesen Knoten <b a="zzz"></b>

41voto

CedCannes Punkte 417

SimpleXML gibt immer Object zurück. Wenn es kein Kind gibt, wird ein leeres Objekt zurückgegeben.

if( !empty($a->b)){
  var_dump($a->b);
}

0 Stimmen

Offensichtlich handelt es sich dabei um eine Funktion und nicht um einen Fehler. Und es ist sehr wichtig, dies zu beachten. Beim Zugriff auf ein untergeordnetes Objekt wird es erstellt, wenn es nicht existiert.

3 Stimmen

Das sollte die akzeptierte Antwort sein, das hätte mir einige Zeit und Frustration erspart :-)

2 Stimmen

Falsche Antwort. Denn empty() gibt zurück. true auch wenn der Knoten zwar existiert, aber keinen Inhalt hat. Wenn zum Beispiel in Ihrem Codebeispiel $a enthält dies: <xml><b a="zzz"/></xml> entonces empty($a->b) wird zurückgegeben true . Daher ist dies keine zuverlässige Methode, um zu prüfen, ob ein Knoten existiert. Sie können verwenden empty() Wenn Sie jedoch etwas innerhalb eines Knotens benötigen, d. h. zwischen > y < und nicht an dem Knoten ohne Inhalt interessiert

9voto

Daniel Howard Punkte 3452

Die Antwort von @null ist richtig - der einfachste Weg, dies zu tun, ist mit isset

if (isset($A->b->c)) { /* c exists */ }

Die Gründe dafür sind jedoch nicht offensichtlich (zumindest für mich), und es gibt eine ganze Reihe von Fehlinformationen auf dieser Seite. Es hat eine Weile gedauert, bis ich es richtig verstanden habe, deshalb wollte ich meine Erkenntnisse weitergeben.

Wie bereits erwähnt, erhalten Sie beim Zugriff auf ein nicht vorhandenes untergeordnetes Element eines SimpleXMLElements eigentlich ein "leeres" SimpleXMLElement, im Gegensatz zu false oder null.

Wenn b also zum Beispiel nicht existiert:

$b = $A->b; // $b is now an empty SimpleXMLElement
$b->getName(); // returns an empty string
isset($b); // returns true

Sie könnten also denken, dass die Verwendung von isset auf das Vorhandensein von Kindern zu testen, wird nicht funktionieren, denn wenn das Kind nicht existiert, erhalten wir immer noch ein leeres SimpleXMLObject, also isset wird zwangsläufig true zurückgeben.

Tatsächlich ist das aber nicht der Fall:

isset($A->b); // returns false

Das war für mich ziemlich überraschend! Der Grund dafür ist, dass isset ist keine reguläre Funktion, sondern ein PHP-Sprachkonstrukt. Wenn Sie die Funktion isset($A->b) PHP berechnet nicht zuerst $A->b und übergeben dann das Ergebnis als Argument an isset() . Stattdessen ist das Verhalten, wenn isset bei einer unzugänglichen Objekteigenschaft aufgerufen wird, der Aufruf der __isset() Überladungsmethode für die Klasse (wie hier erklärt: https://www.php.net/manual/en/language.oop5.overloading.php#object.isset )

So kann der Autor der Klasse das Ergebnis von isset($A->b) unabhängig vom Ergebnis der $b = $A->b . Im Fall von SimpleXMLElement haben sie es so eingerichtet, dass isset($A->b) gibt true zurück, wenn b existiert, und false, wenn nicht - genau das, was wir brauchen, um die Existenz eines untergeordneten Elements zu prüfen.

Eine weitere Fußnote dazu - die ursprüngliche Frage bezog sich auf die Prüfung der Existenz von $A->b->c . Verwendung von isset($A->b->c) funktioniert auch in diesem Fall perfekt, selbst wenn das Zwischenprodukt b nicht existiert. Ich denke, was hier passiert ist, dass PHP zuerst $A->b und wenn b nicht existiert, erhält es ein leeres SimpleXMLElement, dann ruft es __isset('c') auf dieses leere SimpleXMLElement, um das Endergebnis von isset($A->b->c) .

8voto

Artur Bodera Punkte 1651

Nach einigen Experimenten habe ich herausgefunden, dass die einzige zuverlässige Methode zur Überprüfung, ob ein Knoten existiert, die Verwendung von count($xml->someNode) .

Hier ist ein Testfall: https://gist.github.com/Thinkscape/6262156

8voto

scippie Punkte 1874

Ich habe das Problem gelöst, indem ich die children() Funktion und die Durchführung einer count() auf, wobei ein PHP-Fehler ignoriert wird, wenn es keine Kinder gibt, indem ein @ vor den Count-Aufruf gesetzt wird. Das ist dumm, aber es funktioniert:

$identification = $xml->identification;
if (@count($identification->children()) == 0)
  $identification = $xml->Identification;

Ich hasse das

0 Stimmen

Sie haben völlig Recht (deshalb sagte ich "Ich hasse das..."), aber wenn Sie wissen, dass Sie jeden Fehler ignorieren wollen, dann ist das in Ordnung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X