SimpleXML liest Bereich nicht?
hawkmaster
- php
0 Der Martin
0 dedlfix
0 MudGuard
Hallo zusammen,
ich versuche gerade zum ersten mal eine XML Datei mit SimpleXML auszulesen.
Die XML Struktur sieht wie folgt aus:
...
<DeviceOption fixed="Yes">
<!-- ############################################### -->
<feature>
<name>LargeCapacityTray</name>
<displayname>Large Capacity Tray</displayname>
<oidlength>100</oidlength>
<options>
<!-- The following values should be the raw value -->
<!-- , should not be the value by resource DLL. -->
<option value="notinstalled" optionvalue="NotInstalled" displayvalue="Not Installed" dtype="s"/>
<option value="1378" optionvalue="SKAD" displayvalue="Large Tray" dtype="s"/>
<option value="1379" optionvalue="ERIAC" displayvalue="Wide Tray" dtype="s"/>
</options>
<description>This is the Optional Large Capacity Tray</description>
</feature>
<!-- ######################################## -->
<feature>
....
</feature>
</DeviceInstallableOption>
Es gibt also mehrere Bereiche mit <feature>.
Auslesen kann ich bereits ohne Probleme die Elemente "description" und "displayname".
Interessant wären für mich aber vor allem die Bereich <options> und hier dann die einzelnen Werte bei <option>.
Ich habe es so versucht:
foreach($xml->DeviceInstallableOption[0]->feature->options as $opt){
echo $opt->option . "<br />";
}
Das bringt aber keine Ausgabe.
Wenn ich ein var_dump mache sehe ich allerdings die Werte.
var_dump($xml->DeviceInstallableOption[0]->feature->options);
Wie spreche ich diese Elemente richtig an?
$filename = 'test.xml';
if(file_exists($filename)) {
$xml = simplexml_load_file($filename);
if($xml) {
//var_dump($xml->DeviceInstallableOption[0]->feature->options);
foreach($xml->DeviceInstallableOption[0]->feature as $news) {
echo $news->description . "<br />";
echo $news->displayname . "<br />";
echo "<hr />";
}
//versuch die <option> auszulesen
foreach($xml->DeviceInstallableOption[0]->feature->options as $opt){
echo $opt->option . "<br />";
}
} else {
echo '<p>Die Datei names '. $filename .' konnte nicht geöffnet
werden</p>';
}
}//if(file_exists($filename))
vielen Dank und viele Grüße
hawk
Hallo,
Auslesen kann ich bereits ohne Probleme die Elemente "description" und "displayname".
das wundert mich, denn ...
foreach($xml->DeviceInstallableOption[0]->feature->options as $opt)
... du hast doch mehrere feature-Elemente innerhalb eines DeviceOption-Elements. Sie bilden daher ebenfalls ein Array bzw. eine Collection, über die du indizieren bzw. iterieren musst.
Wenn ich ein var_dump mache sehe ich allerdings die Werte.
var_dump($xml->DeviceInstallableOption[0]->feature->options);
Steht das wirklich so in deinem Code? Seltsam.
foreach($xml->DeviceInstallableOption[0]->feature as $news)
Ah, hier passt es noch, du iterierst mit foreach über feature.
foreach($xml->DeviceInstallableOption[0]->feature->options as $opt)
So nicht. Aber $news ist doch an der Stelle bereits eine Referenz auf das aktuelle feature-Element. Warum also nicht einfach foreach ($news as ...)?
So long,
Martin
Hi!
Aber $news ist doch an der Stelle bereits eine Referenz auf das aktuelle feature-Element. Warum also nicht einfach foreach ($news as ...)?
Weil er über $news->options->option iterieren möchte. $news ist ja nur ein Objekt, kein Array (oder eine Traversable-Implementation).
Das ganze Gehampel mit dem Durchhangeln durch die Objekthierarchie kann man übrigens eintauschen gegen XPath-Ausdrücke, so man ihrer mächtig ist.
Lo!
Hallo zusammen,
danke euch für die Hilfe.
Weil er über $news->options->option iterieren möchte. $news ist ja nur ein Objekt, kein Array (oder eine Traversable-Implementation).
ja genau. Ich brauche eigentlich nur die einzelnen Werte die zwischen <option> liegen.
Ein var_dump zeigt mir folgendes an:
------------------------------------------------------
object(SimpleXMLElement)#6 (1) { ["option"]=> array(3) { [0]=> object(SimpleXMLElement)#8 (1) { ["@attributes"]=> array(4) { ["mibvalue"]=> string(12) "notinstalled" ["optionvalue"]=> string(12) "NotInstalled" ["displayvalue"]=> string(13) "Not Installed" ["dtype"]=> string(1) "s" } } [1]=> object(SimpleXMLElement)#7 (1) { ["@attributes"]=> array(4) { ["mibvalue"]=> string(4) "1378" ["optionvalue"]=> string(10) "LCTALASKAD" ["displayvalue"]=> string(19) "Large Capacity Tray" ["dtype"]=> string(1) "s" } } [2]=> object(SimpleXMLElement)#5 (1) { ["@attributes"]=> array(4) { ["mibvalue"]=> string(4) "1379" ["optionvalue"]=> string(11) "LCTSIBERIAC" ["displayvalue"]=> string(24) "Wide Large Capacity Tray" ["dtype"]=> string(1) "s" } } } }
--------------------------------------------------------
Also müssten doch die Werte im XML Objekt drin sein oder?
Ich kapier aber einfach nicht, wie ich die <option> ansprechen kann?
$xml = simplexml_load_file($filename);
if($xml) {
foreach($xml->DeviceInstallableOption[0]->feature as $news) {
echo $news->description . "<br />";
echo $news->displayname . "<br />";
//echo $news->options . "<br />";
var_dump($news->options[0]);
echo "<hr />";
}//foreach
} else {
echo '<p>Die Datei names '. $filename .' konnte nicht geöffnet
werden</p>';
}
vielen Dank und viele Grüße
hawk
Hi!
ja genau. Ich brauche eigentlich nur die einzelnen Werte die zwischen <option> liegen.
Dazwischen? Da liegen nur Zeilenumbrüche. Du meinst sicher die Attribute der option-Elemente. Siehe Basic Usage, Beispiel 5 und SimpleXMLElement::attributes.
Also müssten doch die Werte im XML Objekt drin sein oder?
Ich kapier aber einfach nicht, wie ich die <option> ansprechen kann?
SimpleXML arbeitet mit viel PHP-Magie (Object overloading plus SPL), da helfen einem allgemeine PHP-Kenntnisse nicht unbedingt weiter. Stattdessen sollte man in der Dokumentation nachsehen, wie man bestimmte Elemente anspricht.
Lo!
Hallo dedlfix,
Dazwischen? Da liegen nur Zeilenumbrüche. Du meinst sicher die Attribute der option-Elemente.
Ah, mir dämmert was :-)
ja klar das sind ja alles Attribute die ich suche.
--------------------
<feature>
<name>LargeCapacityTray</name>
<displayname>Large Capacity Tray</displayname>
<options>
<option value="notinstalled" optionvalue="NotInstalled" displayvalue="Not Installed" dtype="s"/>
<option value="1378" optionvalue="SKAD" displayvalue="Large Tray" dtype="s"/>
option value="1379" optionvalue="BERIAC" displayvalue="Wide Capacity Tray" dtype="s"/>
</options>
</feature>
--------------------
SimpleXML arbeitet mit viel PHP-Magie (Object overloading plus SPL)
Das Manual zu SimpleXML lese ich schon.
http://nl3.php.net/manual/de/simplexml.examples-basic.php
Ich hatte auch schon mal nach deinem Vorschlag mit "xpath" was versucht.
foreach ($xml->xpath('/feature') as $character) {
echo $character->name . '<br />';
}
Das ist doch eigentlich fast wie im Manual "Beispiel #8 XPath verwenden".
Eigentlich müsste doch hier nach "feature" gesucht werden und dann das Element <name> ausgegeben werden?
vielen Dank und viele Grüße
hawk
Hi!
foreach ($xml->xpath('/feature') as $character) {
Das Element /feature gibt es in deinem Dokument nicht, /DeviceInstallableOption/feature ergäbe alle feature-Elemente. Absolute Adressierung bewirkt aus jedem Knoten heraus einen absoluten Zugriff auf das gesamte Dokument. Von $xml kannst du relativ auf feature oder feature/name zugreifen. und von $news relativ auf options und options/option, und so weiter.
Lo!
Hallo
SimpleXML arbeitet mit viel PHP-Magie (Object overloading plus SPL), da helfen einem allgemeine PHP-Kenntnisse nicht unbedingt weiter. Stattdessen sollte man in der Dokumentation nachsehen, wie man bestimmte Elemente anspricht.
So viel Magie war es dann doch nicht :-)
Mein Denkfehler war einfach das ich ja eigentlich nach den Attributen gesucht habe. Ich muss also das Objekt mit dem Attributnamen ansprechen.
So geht es nun:
foreach($xml->DeviceInstallableOption[0]->feature as $news) {
echo $news->displayname . "<br />";
foreach($news->options->option as $opt){
echo $opt['displayvalue'] . "<br />";
}
echo "<hr />";
}
vielen Dank und viele Grüße
hawk
Hi!
SimpleXML arbeitet mit viel PHP-Magie (Object overloading plus SPL), da helfen einem allgemeine PHP-Kenntnisse nicht unbedingt weiter. Stattdessen sollte man in der Dokumentation nachsehen, wie man bestimmte Elemente anspricht.
So viel Magie war es dann doch nicht :-)
Aber genug, um jenseits der üblichen PHP-Regeln zu landen. Du hast ein Objekt und greifst mit -> auf seine Eigenschaften zu. Soweit ist das normal. Zusätzlich kannst du mit dem Array-Zugriff ['name'] auf Dinge zugreifen, die gar nicht direkt im Objekt enthalten sind, sondern in einer seiner Eigenschaften. So sieht das erste <option...> aus, wenn man es var_dump()t.
object(SimpleXMLElement)#6 (1) {
["@attributes"]=>
array(4) {
["value"]=>
string(12) "notinstalled"
["optionvalue"]=>
string(12) "NotInstalled"
["displayvalue"]=>
string(13) "Not Installed"
["dtype"]=>
string(1) "s"
}
}
Man sieht eine Eigenschaft namens @attributes - mit @ vorndran. Das kann man schon mal nicht auf einfachem Wege mit ->@attributes ansprechen sondern benötigt ->{@attributes} - was jedoch immer noch PHP-konform ist. Ein var_dump($option->{@attributes}) sollte nun das Array mit seinen 4 Elementen ergeben. Aber Pustekuchen, man bekommt mit object(SimpleXMLElement)#8 (0) {} ein leeres Objekt. Auch der Durchgriff mit $option->{@attributes}['value'] schlägt fehl - und zwar ohne Fehlermeldung, das ergibt einfach nur NULL als Ergebnis. Man muss das $option als nicht sichtbares Array ansprechen: $option['value'] und bekommt dann - Überraschung! keinen String sondern ein
object(SimpleXMLElement)#8 (1) {
[0]=>
string(12) "notinstalled"
}
Wundersamerweise per echo ausgegeben ergibt das dann: notinstalled. Also wenn da nicht jede Menge Magie verbaut ist, ...
SimpleXML ist zwar der einfachste Weg, um auf XML zuzugreifen, aber zugleich der am wenigsten offensichtliche.
Lo!
Hallo dedlfix,
vielen Dank erst einmal für deine tolle Erklärung und Analyse.
SimpleXML ist zwar der einfachste Weg, um auf XML zuzugreifen, aber zugleich der am wenigsten offensichtliche.
ja da hast du recht. Ich konnte auch mit dem var_dump nicht so richtig was anfangen.
Mich hatte dann doch auch das Konstrukt;
foreach($news->options->option as $opt){
etwas gewundert. Aber nur so habe ich es hinbekommen.
Insofern hast du mit "Magie" schon sehr recht.
vielen Dank und viele Grüße
hawk
Hi,
<DeviceOption fixed="Yes">
<!-- ############################################### -->
<feature>
....
</feature>
</DeviceInstallableOption>
Paßt irgendwie nicht zusammen - DeviceOption wird geöffnet, aber DeviceInstallableOption wird geschlossen.
Ich habe es so versucht:
foreach($xml->DeviceInstallableOption[0]->feature->options as $opt){
Laut Anfang des Beispiel-XMLs liegen die feature-Elemente nicht in DeviceInstallableOption ...
cu,
Andreas
Hallo Andreas,
danke für den Hinweis und für die Hilfe.
Paßt irgendwie nicht zusammen - DeviceOption wird geöffnet, aber DeviceInstallableOption wird geschlossen.
sorry, das war ein Fehler von mir der bei Copy und Paste passiert ist.
Es heist natürlich
<DeviceInstallableOption fixed="Yes">
...
</DeviceInstallableOption>
vielen Dank und viele Grüße
hawk