Gå til innhold

Parse mappe med 400 XML filer


Anbefalte innlegg

Hey,

 

Jeg har installert XML::Simple, og har lekt meg litt med dette de siste dagene.

 

Det er ingen problemer med å parse en enkelt fil, men jeg ønsker å lese inn en mappe med 400 xml filer som alle skal parses en etter en.

De har samme oppbygging, og derfor trenger jeg bare et script som leser en og en fil.

 

Problemet er at følgende script ikke fungerer:

 

#!/usr/bin/perl

use XML::Simple;
use Data::Dumper;

$xml = new XML::Simple(keeproot => 1, searchpath => "../xml/");

# Sorterer filnavnet
my @files = `ls -l ../xml/ | sort -t "-" -k3`;

foreach $file (@files){
  $data = $xml->$XMLin("$file");
  print "Navn:\n$data->{body}->{content}\n";
}

 

Følgende script fungerer:

 

#!/usr/bin/perl

use XML::Simple;
use Data::Dumper;

$xml = new XML::Simple(keeproot => 1, searchpath => "../xml/");

# Sorterer filnavnet
my $filen = "XXX-12345678-112233445566-112233.xml";

$data = $xml->$XMLin("/home/hoved/Desktop/xml/$filen");

print "Navn:\n$data->{body}->{content}\n";

 

blir sprø!

 

Noen som vet hvordan man kan parse alle xml filer i en enkelt mappe?

 

OS: Debian

 

Håper på raskt svar ;)

Endret av Haavard82
Lenke til kommentar
Videoannonse
Annonse
Du burde virkelig vurdere å bruke

use warnings;
use strict;

det tar en del vanlige feil (perl.com intro)

 

Har ikke XML::Simple tilgjengelig, men når jeg kjører koden din på bsd blir $file satt til snodige ting.. har du printa den ut?

 

Da satte jeg på warnings og strict..

 

Resulatet er at jeg får følgende error på variablene:

$xml, $file og $data:

 

Global Symbol "<variabel nevnt ovenfor>" requires explicit package name at ./xmlscript.pl line xx"

 

Det virker som at man da bare kan gi filnavnet direkte, og ikke ved hjelp av en foreach e.l ?

 

Enig i det?

 

Jeg fikk ikke de snodige tingene dine.

Har du installer CPAN XML::Simple pakkene o.l? Var en del drit for å få installert alt det nødvendige.

 

Men ja, det må da være en eller annen mulighet når vi er i 2010 til å parse flere XMl filer? lættis hvis ikke!

Endret av Haavard82
Lenke til kommentar

Kan det være fordi $xml-objektet ditt ikke er muterbart? at du må lukke det eller reinitialisere det på nytt før du laster inn neste fil...

 

Du må også initialisere variablene dine...

"my $xml; my $file; my $data;"

 

Og en annen ting jeg har lært av perl er at selv om et bibliotek heter "::Simple", så betyr det ikke nødvendigvis at det faktisk _er_ "simple" ;)

 

-C-

Lenke til kommentar
Kan det være fordi $xml-objektet ditt ikke er muterbart? at du må lukke det eller reinitialisere det på nytt før du laster inn neste fil...

 

Du må også initialisere variablene dine...

"my $xml; my $file; my $data;"

 

Og en annen ting jeg har lært av perl er at selv om et bibliotek heter "::Simple", så betyr det ikke nødvendigvis at det faktisk _er_ "simple" ;)

 

-C-

 

 

Jeg har tatt hensyn til det du har skrevet, og laget et nytt script:

 

#!/usr/bin/perl
use warnings;
use strict;
use XML::Simple;
use Data::Dumper;

my $data; my $xml; my $files; my $file;

$xml = new XML::Simple(keeproot => 1, searchpath => "../xml/");

my @files =  `ls -1 ../xml/ | sort -t "-" -k3`;

foreach $files (@files){

open FILE, ">", "../xml/$files" or die $!;
print $data = $xml->XMLin("../xml/$files");
close(FILE);

print "Output er: $data->{body}->{main}->{info}->{content}\n";
}

 

Nå får jeg error:

Ran out of memory for input buffer at /usr/lib/perl5/XML/Parser/Expat.pm line 469.

 

Noen idèer?

Jeg har forsøkt å søke på denne feilen på google, uten å finne noe.

Virker nesten umulig dette! :(

 

PS!

Når jeg kommenterte ut denne linjen:

"# print $data = $xml->XMLin("../xml/$files");"

 

Så kjører scriptet, og gir meg en linje i terminalen for hver fil den har i arrayen @files:

 

"$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;

$VAR1 = undef;"

 

osv.....

 

Det virker som at det er her feilen ligger:

"XMLin("../xml/$files");"

 

Om jeg skriver navnet på en XML fil inni XMLin() vil filen parses korrekt, det er altså det å gi navnet via en variabel som feiler virker det som?

Endret av Haavard82
Lenke til kommentar
Det var ikke filen jeg tenkte på om du lukket eller ikke, men XML-objektet.

 

Hiv på en linje som sier "print $files;" inne i loopen og sørg for at du får ut korrekte filnavn.

Iterering og variabler og referanser og pekere og og og og... i perl... *sukk* ;)

 

-C-

 

Jeg har laget en print $files inni loopen, og jeg får ut riktige filnavn.

Dukker opp en feilmelding om at filen ikke finnes når jeg bruker den samme variabelen inni XMLin().

Jeg har forsøkt å skrive mappestien osv uten at det hjelper.

Det er fryktelig fryktelig rart!

 

Jeg er redd jeg ikke helt ser hva du mener med resten av det du skriver.

Kunne du være så kjempesnill å skrive om scriptet for meg ?

 

Jeg lærer fort, og vil skjønne vitsen.

Det vil sikkert være veldig nyttig for andre som søker opp dette emnet senere :)

Endret av Haavard82
Lenke til kommentar

Jeg er nok ikke den rette til å skrive om scriptet til deg da jeg hater perl intenst ;)

Jeg har brukt perl endel iforbindelse med xmltv (se sig) og har det langt oppi halsen.

 

Når jeg har lest xml har jeg derimot brukt LibXML.

 

Iflg http://search.cpan.org/~grantm/XML-Simple-...mple.pm#XMLin() så kan du sette mapper hvor den skal lete etter XML-filer, for deretter å ikke benytte den fulle banen i XMLin(). hva om du prøver å gjøre det på den måten?

 

-C-

Lenke til kommentar
Jeg er redd jeg ikke helt ser hva du mener med resten av det du skriver.

Kunne du være så kjempesnill å skrive om scriptet for meg ?

 

jeg tror han mener du skal opprette XML::Simple inni loop'en, altså

 

foreach blablabla {
  $xml = new XML::Simple(keeproot => 1, searchpath => "../xml/");
  open FILE ... osv.
}

 

hvis XML::Simple er immutable betyr det at egenskapene, f.eks. hvilken fil som skal parses, ikke kan endres på en gitt instans. skal du parse en ny fil må du opprette en ny instans.

 

eventuelt er det sånn at et eller annet må initialiseres før eller etter at du leser inn ny fil. det står vel i tilfelle i dokumentasjonen?

 

selv om du har satt på strict og postet hvilke meldinger du da får kan jeg ikke se at du egentlig har fortalt hva du mener med "virker ikke". Får du feil, krasj, printes samme navn ut for hver loop eller hva?

 

du skriver også at du får loopen til å gå rundt om du kommenterer ut kodelinja som faktisk parser fila, og at filnavnet i $files er riktig.

 

prøv å opprette ny instans av xml-objektet inni løkka og se om det hjelper.

 

eventuelt prøv en variant av det første skriptet ditt, men med to statiske filnavn istedenfor ett. da får du sjekket dette med immutability og initialisering, uten at du bruker foreach.

Endret av quantum
Lenke til kommentar
foreach $files (@files){

open FILE, ">", "../xml/$files" or die $!;
print $data = $xml->XMLin("../xml/$files");
close(FILE);

print "Output er: $data->{body}->{main}->{info}->{content}\n";
}

...

PS!

Når jeg kommenterte ut denne linjen:

"# print $data = $xml->XMLin("../xml/$files");"

...

Det virker som at det er her feilen ligger:

"XMLin("../xml/$files");"

 

Om jeg skriver navnet på en XML fil inni XMLin() vil filen parses korrekt, det er altså det å gi navnet via en variabel som feiler virker det som?

 

Når jeg leser dette kommer jeg på et par ting til.

 

fjern "print" fra

print $data = $xml->XMLin("../xml/$files");

 

da har du ihvertfall rydda vekk en ting du egentlig ikke skal ha med i det ferdige scriptet, og dermed en feilkilde. tror ikke dette er problemet, men lurt å strippe vekk mest mulig.

 

du skriver at du tror feilen ligger i kodelinja ovenfor her, siden det går rundt når du kommenterer ut denne. men det kan vel like godt hende at problemet ligger i xpath-linja hvor du printer ut Navn. xpath-søket går fint når det ikke er noe innhold å søke i, men du får faktisk en out-of-memory feil når du bruker xpath til å søke fram verdien du skal printe ut. feilen oppstår jo i Expat.pm - som jeg *gjetter* inneholder funksjon for å utføre xpath-søk i eksisterende (innleste og dom-parsede) dokumenter. for å verifisere dette kan du kanskje legge inn en liten debug-utskrift innimellom de andre linjene i foreach-loopen a'la "print "ok so far (1)"; blablabal; print "ok so far (2)"; blabla; osv. Eventuelt bruke en debugger.

 

det hadde vært interessant å visst om du får feil allerede i første runde av loop'en, eller om du får out-of-memory feil først etter at det har gått bra noen omganger. isåfall ville jeg gjette at koden din leser inn og *legger til* nye xml-dokumenter i xml-objektet uten å ta vekk det som ligger der fra før, altså at dokumentet som xpath-søken kjøres i vokser for hver runde og til slutt blir så stort at minnet sprekker.

Lenke til kommentar

Denne fungerte for meg:

 

#!/usr/bin/perl
use warnings;
use strict;
use XML::Simple;
use Data::Dumper;

my $data; my $xml; my $file; my @files;

$xml = new XML::Simple(keeproot => 1, searchpath => "../xml/");

opendir(DIR, "../xml");
@files = readdir(DIR);
closedir(DIR);

foreach $file (@files){
 next if ($file eq "." or $file eq "..");
 print $file . "\n";
 $data = $xml->XMLin($file);
 print "Output er:" . $data->{opt}->{person} . "\n";
}

 

1. jeg fikk ikke kjørt i utgangspunktet i strict når @files ikke var deklarert.

 

2. omnavnet $files til $file, siden det er navnet på en fil og ikke en liste.

 

3. katalogparsinga di med ls osv. fikk jeg ikke til å gi noe fornuftig. print $file; inni loopen så ikke riktig ut når jeg kjørte dette. muligens kan du ha fått out of memory feil når du har prøvd å lese inn "." eller ".." som en xmlfil. mulig du skal legge på open og close igjen.

 

4. du trenger ikke ha med stiveien til fila når du åpner den iom. at root blir satt når du instansierer xml-objektet. (du må derimot ha med hele stiveien dersom du legger inn open FILE igjen. Edit: Gjetter at du ikke trenger iom. at det ikke er vist i eksemplene i dokumentasjonen.

 

5. jeg hater også perl nå.

 

6. EDIT: Det funker også med

 

my @files =  `ls -1 ../xml/ | sort -t "-" -k3`;
chop(@files);

 

det ser altså ut som du får med en newline i filnavnene som du må ta vekk.

Endret av quantum
Lenke til kommentar
Det er ingen problemer med å parse en enkelt fil, men jeg ønsker å lese inn en mappe med 400 xml filer som alle skal parses en etter en.

 

Litt sent, og kanskje jeg har misforstått noe..

Men for x in *.xml; do script.pl "$x"; done burde vel klare den biffen fint?

Endret av Terrasque
Lenke til kommentar
Det er ingen problemer med å parse en enkelt fil, men jeg ønsker å lese inn en mappe med 400 xml filer som alle skal parses en etter en.

 

Litt sent, og kanskje jeg har misforstått noe..

Men for x in *.xml; do script.pl "$x"; done burde vel klare den biffen fint?

 

Eller hvis det er flere undermapper eller at noen av filnavnene har blanke i seg:

 

find . -name '*.xml' -print0 | xargs -0 script.pl

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...