SimpleXML -> Array
Sascha Mux
- php
0 Alexander (HH)0 frankx0 Sascha Mux
Hallo,
ich versuche schon länger sowas simples wie ein Array zu durchlaufen und alle (SimpleXMLElement) Objekte in ein Array umzuwandeln -- und zwar ALLE Objekte, egal wie verzweigt der Baum ist. Ich bekomm es nicht nicht.
Bis bald,
Sascha
Moin Moin!
Arbeite rekursiv oder mit einer To-Do-Liste.
Beispiel für Dateibäume, in ungeprüftem Perl.
# Rekursiv:
sub scan
{
my $where=shift;
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";
my @items=$dir->read();
$dir->close(); # Handles gibt es nur begrenzt, also schnell wieder freigeben
foreach my $item (@items) {
if (-d "$where/$item") {
scan("$where/$item");
} else {
print "Datei: $where/$item\n";
}
}
# TO-DO-Liste:
sub scan
{
my $start=shift;
my @todo=($start);
while (@todo) {
my $where=shift @todo;
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";
while (my $item=$dir->read()) {
if (-d "$where/$item") {
push @todo,"$where/$item";
} else {
print "Datei: $where/$item\n";
}
}
$dir->close();
}
}
Alexander
Hellihello
<?php
function overview ($dir) {
foreach(scandir($dir) as $dir_or_file) {
if (strpos($dir_or_file,".")!==0) {
if (is_dir($dir.'/'.$dir_or_file)) {
echo "<li>$dir_or_file<ul>\n";
overview($dir.'/'.$dir_or_file);
echo "</ul></li>\n";
}
else {
echo "<li>$dir_or_file</li>\n";
}
}
}
}
overview(".");
?>
Rekursiv:
sub scan
{
my $where=shift;
was ist "shift"?
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";
Was ist IO::Dir? Was ist $! ?
my @items=$dir->read();
$dir->close(); # Handles gibt es nur begrenzt, also schnell wieder freigeben
foreach my $item (@items) {
if (-d "$where/$item") {
-d heißt "is_dir()"?
scan("$where/$item");
} else {
print "Datei: $where/$item\n";
}
}
heißt: du erzeugst ein Array mit allen Ordnerpfaden, die durchsucht werden wollen?
TO-DO-Liste:
sub scan
{
my $start=shift;
my @todo=($start);
while (@todo) {
my $where=shift @todo;
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";
while (my $item=$dir->read()) {
if (-d "$where/$item") {
push @todo,"$where/$item";
} else {
print "Datei: $where/$item\n";
}
}
$dir->close();
}
}
Dank und Gruß,
[frankx](http://community.de.selfhtml.org/visitenkarten/view.php?key=82)
--
[tryin to](http://sauer-ernst.de) [multitain](http://multitain.de) - Globus = Planet != Welt
Moin Moin!
was ist "shift"?
Ohne Parameter in einer Funktion: erstes Element aus der Parameterliste entfernen und zurückgeben.
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";Was ist IO::Dir?
OOP-verpacktes Directory-Handle, hat u.a. den netten Nebeneffekt, das es sich beim Verlassen des Scopes selbst schließt, wie auch IO::File. So lungern keine offenen Handles herum.
Was ist $! ?
OS-Error, Code im numerischen Kontext, Fehlermeldung im String-Kontext, true bei Fehlern im Bool-Kontext.
my @items=$dir->read();
$dir->close(); # Handles gibt es nur begrenzt, also schnell wieder freigeben
foreach my $item (@items) {
if (-d "$where/$item") {-d heißt "is_dir()"?
heißt: du erzeugst ein Array mit allen Ordnerpfaden, die durchsucht werden wollen?
In der Variante mit der TO-DO-Liste, ja.
Alexander
Hellihello Alexander
Moin Moin!
was ist "shift"?
Ohne Parameter in einer Funktion: erstes Element aus der Parameterliste entfernen und zurückgeben.
print "Verzeichnis: $where\n";
my $dir=IO::Dir->new($where) or die "$where: $!";Was ist IO::Dir?
OOP-verpacktes Directory-Handle, hat u.a. den netten Nebeneffekt, das es sich beim Verlassen des Scopes selbst schließt, wie auch IO::File. So lungern keine offenen Handles herum.
Was ist $! ?
OS-Error, Code im numerischen Kontext, Fehlermeldung im String-Kontext, true bei Fehlern im Bool-Kontext.
my @items=$dir->read();
$dir->close(); # Handles gibt es nur begrenzt, also schnell wieder freigeben
foreach my $item (@items) {
if (-d "$where/$item") {-d heißt "is_dir()"?
heißt: du erzeugst ein Array mit allen Ordnerpfaden, die durchsucht werden wollen?
In der Variante mit der TO-DO-Liste, ja.
Alexander
Dank und Gruß,
Hellihello Alexander,
damned, zu früh auf den Returner gekommen (na besser, als alles wech (;-)).
was ist "shift"?
Ohne Parameter in einer Funktion: erstes Element aus der Parameterliste entfernen und zurückgeben.
Das heißt, die Funktion wird auch ohne Parameter definiert. Und dann mit scan(".") gestartet.
OOP-verpacktes Directory-Handle, hat u.a. den netten Nebeneffekt, das es sich beim Verlassen des Scopes selbst schließt, wie auch IO::File. So lungern keine offenen Handles herum.
Bei PHP wären das scandir(), glob() bzw. bei Dateien dann file_get|put_contents(), die die Handles von allein wieder freigeben?
Vermutlich muss auch ein Standardincludepfad zu den cpan-Klassen gesetzt sein? Gibts eine perl.ini?
Was ist $! ?
OS-Error, Code im numerischen Kontext, Fehlermeldung im String-Kontext, true bei Fehlern im Bool-Kontext.
Heißt dann im Ergebnis "blablub: is not a directory".
Dank und Gruß und gute Nacht,
Moin Moin!
was ist "shift"?
Ohne Parameter in einer Funktion: erstes Element aus der Parameterliste entfernen und zurückgeben.
Das heißt, die Funktion wird auch ohne Parameter definiert.
Perl ist recht entspannt, was Funktionsparameter angeht. Eine explizite Deklaration von Parametern wie z.B. in C (z.B. int myscan(char * startdir)
) ist nicht notwendig. Es gibt die Möglichkeit, sogenannte Prototypen zu benutzen, um den Funktionsaufruf zu vereinfachen, eine rudimentäre Prüfung der Parameter findet dann auch statt. Aber erstens kann man das per &funktion() aushebeln und zweitens funktioniert das nicht für Methodenaufrufe. Deswegen benutzt man Prototypen nur für sehr spezielle Anwendungsfälle, und deswegen ist die alte Perl4-Syntax eines Funktionsaufrufs mit vorangestelltem Ampersand nicht gerne gesehen.
Javascript ist bei Parametern IMHO noch viel schlimmer: Es täuscht vor, man könnte die Anzahl der Parameter vorgeben, und es täuscht vor, es gäbe keine varargs. In Wirklichkeit findet wie in Perl keine Prüfung statt, man kann die Prüfung aber nicht einmal erzwingen. Man kann eine JS-Funktion, die drei Parameter deklariert, ohne Fehler oder Warnung mit jeder beliebigen Anzahl von Parametern aufrufen. Die deklarierten Parameter ersparen lediglich das Deklarieren und Umkopieren der ersten n Elemente von arguments
in lokale Variablen -- was zugegebenermaßen im Normalfall etwas eleganter als das manuelle Umkopieren in Perl ist.
Das Analogon zu Javascripts arguments
ist Perls @_, lang und breit in perldoc perlsub erklärt.
Und dann mit scan(".") gestartet.
Oder mit scan("/wo/auch/immer"). Eine kleine Erweiterung der TO-DO-Listen-Variante kann die TO-DO-Liste mit allen Parametern initialisieren, so wäre dann auch ein scan("/hier","/da","/dort") möglich.
OOP-verpacktes Directory-Handle, hat u.a. den netten Nebeneffekt, das es sich beim Verlassen des Scopes selbst schließt, wie auch IO::File. So lungern keine offenen Handles herum.
Bei PHP wären das scandir(), glob() bzw. bei Dateien dann file_get|put_contents(), die die Handles von allein wieder freigeben?
Keine Ahnung, ich fasse PHP nur in höchster Not an.
scandir() und glob() sind Funktionen aus der C Standard Library, die werden den Handle definitiv selbst wieder freigeben, wenn PHP da nicht irgendwelche bizarren Spielchen treibt.
Das schöne an IO::Handle und seinen Derivaten (IO::File, IO::Dir, ...) ist, dass das Handle implizit geschlossen wird, sobald man aus dem Scope herausläuft. Sehr nützlich ist das besonders, wenn man im Fehlerfall einfach ein return macht. Damit erspart man sich, je nach Position in der Funktion ein, zwei, drei oder vier Handles schließen zu müssen.
# dirlist soll ein Verzeichnis auslesen und eine Liste aller Einträge
# zurückliefern, im Fehlerfall eine leere Liste.
# klassisch ohne IO::Handle
sub dirlist
{
my $dirname=shift;
local *DIR; # Handles passen nicht in normale Variablen, müssen in lokalisierten globs gepackt werden -- Altlast aus Perl4
opendir DIR,$dirname or return;
my @retval=readdir DIR;
closedir DIR;
return @retval;
}
# IO::Dir, noch sehr klassisch
use IO::Dir; # einmal am Script-/Modulanfang
sub dirlist
{
my $dirname=shift;
my $dir=IO::Dir->new($dirname) or return; # IO::Dir->new() liefert eine stinknormale Objektreferenz
my @retval=$dir->read();
$dir->close();
return @retval;
}
# IO::Dir, mit automatischem close
sub dirlist
{
my $dirname=shift;
my $dir=IO::Dir->new($dirname) or return;
my @retval=$dir->read();
return @retval;
# $dir->close() geschieht implizit während des returns,
# weil $dir aus dem Scope von dirlist herausläuft,
# dadurch automatisch $dir->DESTROY() aufgerufen wird,
# was letztlich $dir->close() aufruft,
# sofern das Handle in $dir noch geöffnet ist.
}
# IO::Dir, noch etwas kürzer, ohne umständliches Umkopieren
sub dirlist
{
my $dir=IO::Dir->new(shift) or return;
return $dir->read();
# $dir->close() geschieht automatisch, s.o.
}
# Der Scope kann auch ein Block innerhalb einer Funktion sein:
sub arbeite
{
my @list;
# klassisch:
@list=dirlist("/hier");
# kleiner Block, $dir wird am Ende des Blocks ggf. automatisch geschlossen
@list={ my $dir=IO::Dir->new("/da"); $dir ? $dir->read() : () };
}
Vermutlich muss auch ein Standardincludepfad zu den cpan-Klassen gesetzt sein?
Ja, typischerweise fest eincompiliert ins perl-Executable, aber zur Aufrufzeit und zur Laufzeit erweiterbar. Kommandozeilen-Parameter -I, Spezial-Variable @INC, Pragma lib, Environment-Variablen PERL5LIB, Fallback auf PERLLIB, nicht im Taint-Modus. Windows-Ports von ActiveState haben Einstellungen in der Registry, die die eincompilierten Werte überschreiben.
Gibts eine perl.ini?
Nein, jedenfalls keine für Perl relevante. Die ist auch nicht notwendig, denn vieles, was bei PHP (und Perl4) fest eincompiliert ist, und dann mühsam konfiguriert werden muß, ist bei Perl5 (und Perl6) in externe Module ausgelagert, die ggf. ihre eigene Konfiguration haben.
Perl (der Interpreter) wird grundlegend beim Compilieren konfiguriert, die Einstellungen kann man zur Laufzeit aus dem Config-Modul auslesen.
Was ist $! ?
OS-Error, Code im numerischen Kontext, Fehlermeldung im String-Kontext, true bei Fehlern im Bool-Kontext.
Heißt dann im Ergebnis "blablub: is not a directory".
Nicht ganz:
perl -e 'opendir DIR,"gibtshiernicht" or die $!'
No such file or directory at -e line 1.
Die $!-Fehlermeldungen enthalten niemals den Namen, damit man die Fehler per RegExp abfragen kann.
Syntax-Warnungen und Fehler enthalten Code-Auszüge, ebenso Fehlermeldungen von require und use, was zwar zur manuellen Diagnose sehr angenehm ist, aber bei automatisiertem Nachladen schonmal nerven kann.
Um den Namen in die $!-Fehlermeldung zu bekommen, muß man ihn explizit mit in die Argumente von die nehmen:
perl -e 'opendir DIR,"gibtshiernicht" or die "gibtshiernicht: $!"'
gibtshiernicht: No such file or directory at -e line 1.
Typischerweise hat man den Dateinamen in einer Variablen, dann sieht es wieder etwas übersichtlicher aus:
perl -e 'my $dn="gibtshiernicht"; opendir DIR,$dn or die "$dn: $!"'
gibtshiernicht: No such file or directory at -e line 1.
Alexander
Hallo,
für mich ist es sehr schwierig zu verstehen was dort steht, da ich kein Perl behersche. Einfacher wäre es für mich Pseudocode gewesen.
Bis bald,
Sascha