SimpleXML: Existenz eines Elementes feststellen, DTDs
Harry
- php
Holladiewaldfee,
ich bastel grade ein bißchen mit SimpleXML rum.
Als Beispiel parse ich eine XML-Datei die vereinfacht ungefähr folgende Struktur hat:
<e1>
<e2/>
</e1>
Das Element e2 muß nicht unbedingt in e1 vorkommen, kann es aber durchaus, wenn es denn Lust hat.
$oXML = simplexml_load_file("test.xml");
$oE1 = &$oXML->e1;
Jetzt möchte ich wissen, ob der Knoten e1 ein Unterelement e2 besitzt.
Wie kann ich das nun am dümmsten machen?
Im Moment behelfe ich mir mit einer XPath-Query auf e1:
if(count($oE1->xpath('e2'))>0) ...
Geht das nicht auch irgendwie eleganter? Abfragen der Art isset($oE1->e2) oder is_object($oE1->e2) scheinen sinnlos, da PHP die SimpleXML-Sachen intern irgendwie so verwaltet (Typ SimpleXMLObject), daß solche Abfragen immer erfolgreich sind, egal ob $oE1->e2 nun existiert oder nicht. Bleibt da wirklich nur der unschöne Weg über XPath?
Zweite Frage:
Kann man den SimpleXML-Parser dazu überreden, die zur XML-Datei gehörige DTD zu berücksichtigen, sofern diese extern in einer Datei abgelegt ist? Standardmäßig scheint er die nämlich einfach zu übergehen, was sehr unschön ist, vor allem da er dann angeblich nicht definierte Entities anmeckert.
Danke schonmal.
Ciao,
Harry
Hallo,
Jetzt möchte ich wissen, ob der Knoten e1 ein Unterelement e2 besitzt.
Ich habe keine Ahnung, wie sich das mit SimpleXML lösen lässt. Wahrscheinlich aus dem Grund, weil es keine Möglichkeit gibt.
Wenn du allerdings sowieso auf komplexere Techniken wie XPath ausweichst, kannst du gleich die DOM-Extension benutzen. Überhaupt ist die DOM-Extension das Mittel der Wahl, wenn man mit XML-Dateien in dieser Weise arbeitet.
Geht das nicht auch irgendwie eleganter?
$doc = new DOMDocument();
$ergebnis = $doc->load('test.xml');
if ($ergebnis) {
$e1 = $doc->getElementsByTagName('e1')->item(0);
if ($e1->getElementsByTagName('e2')->length > 0) {
echo('e2 existiert');
} else {
echo('e2 existiert nicht');
}
}
Oder ähnlich.
Kann man den SimpleXML-Parser dazu überreden, die zur XML-Datei gehörige DTD zu berücksichtigen, sofern diese extern in einer Datei abgelegt ist? Standardmäßig scheint er die nämlich einfach zu übergehen, was sehr unschön ist, vor allem da er dann angeblich nicht definierte Entities anmeckert.
Mit DOM:
$doc = new DOMDocument();
$doc->resolveExternals = true;
$doc->substituteEntities = true;
$ergebnis = $doc->load('test.xml');
...
Mathias
Jetzt möchte ich wissen, ob der Knoten e1 ein Unterelement e2 besitzt.
Ich habe keine Ahnung, wie sich das mit SimpleXML lösen lässt. Wahrscheinlich aus dem Grund, weil es keine Möglichkeit gibt.
Es gibt strenggenommen durchaus Möglichkeiten, zu überprüfen, ob ein solches Element existiert.
In SimpleXML wird davon ausgegangen, dass es im Markup einfache Zuordnungen zwischen Elementen und deren Textinhalt gibt. Daher ist ein Beispiel mit dem leeren Element sowieso keines, wofür SimpleXML geeignet wäre, wenn es sich um ein naturgemäß leeres Element handelt. Man würde, wenn man unbedingt SimpleXML nutzen will, das Element obligatorisch machen und z.B. <e2>true</e2> oder <e2>false</e2> notieren.
Jedes nicht existente Elemente ist gemäß diesem Konzept von SimpleXML dasselbe wie jedes leere Elements, nämlich ein leerer String. In jedem Kontext, in dem ein String erwartet wird, wird das SimpleXMLObject eines nicht vorhandenen Elements also zu einem leeren String. Daher wäre unter der Voraussetzung, dass e2 immer einen Textinhalt hat, wenn es existiert, folgendes denkbar:
if ($oE1->e2 != '') {
echo('Element existiert (und hat Textinhalt)');
}
Man könnte auch alle Kindobjekte durchlaufen und überprüfen, ob ein e2-Element darunter ist:
$element_gefunden = false;
foreach ($oE1 as $element => $wert) {
if ($element = 'e2') {
$element_gefunden = true;
break;
}
}
Eine Unterscheidung zwischen »existent, aber leer« und »nicht existent« ist hier direkt möglich. Das Element kann ruhig leer sein.
Gegenüber deinen XPath-Abfragen ist das natürlich nicht sonderlich eleganter.
Das nur der Vollständigkeit halber, da jemand einwenden könnte, es funktioniere entgegen meiner Aussage. Wie gesagt lohnt sich SimpleXML eher bei bestimmten Markup-Datenstrukturen. Man kann freilich das Markup anpassen, oder aber direkt DOM-Methoden einsetzen.
Mathias
Holladiewaldfee Mathias,
erstmal vielen Dank für Deine Antworten.
Ich werde mich wohl etwas intensiver mit den DOM-Extensions beschäftigen, die scheinen mir doch geeigneter, auch wenn sie auf den ersten Blick durch ihre Funktionsvielfalt und die eher mangelhafte Dokumentation etwas abschreckend wirken.
Es gibt strenggenommen durchaus Möglichkeiten, zu überprüfen, ob ein solches Element existiert.
Ich werde es im Moment einfach mal bei der XPath-Query lassen, bis ich den Code auf DOM umgestellt habe. Im Moment bin ich aber erstmal glücklich, daß es halbwegs läuft. Auf Dauer scheint mit DOM aber doch viel geeigneter zu sein, da die Möglichkeiten mit SimpleXML - wie der Name schon sagt - doch sehr beschränkt sind.
Jedes nicht existente Elemente ist gemäß diesem Konzept von SimpleXML dasselbe wie jedes leere Elements, nämlich ein leerer String.
Sprich: SimpleXML ist im Normalfall eher Müll. Gut, ist ja auch als experimentell gekennzeichnet, aber das sind die DOM-Extensions und MySQLi auch. Zusammen mit der Unfähigkeit, externe DTDs zu laden (ob er interne berücksichtigt, habe ich nicht überprüft), macht das aber für mich den entscheidenden Schritt in Richtung "überflüssig und unbrauchbar" aus.
Wobei ich dann eher erstaunt feststellen mußte, daß Mozilla bei XML-Dokumenten auch (fast) keine externen DTDs lädt - neben den unzähligen Druck-Bugs wieder ein dicker Minuspunkt für Mozilla :-(
Man könnte auch alle Kindobjekte durchlaufen und überprüfen, ob ein e2-Element darunter ist:
Diese Möglichkeit hatte ich auch schon in Betracht gezogen, da finde ich aber wie Du schon gesagt hast die XPath-Methode fast noch eleganter.
Danke Dir auf jeden Fall für Deine Hilfe.
Ciao,
Harry