我正在尝试解析位于一个目录的子目录中的特定XML文件。由于某种原因,我收到错误说文件不存在。如果文件不存在,则应该转到下一个子目录。
这是我的代码
use strict;
use warnings;
use Data::Dumper;
use XML::Simple;
my @xmlsearch = map { chomp; $_ } `ls`;
foreach my $directory (@xmlsearch) {
print "$directory \n";
chdir($directory) or die "Couldn't change to [$directory]: $!";
my @findResults = `find -name education.xml`;
foreach my $educationresults (@findResults){
print $educationresults;
my $parser = new XML::Simple;
my $data = $parser->XMLin($educationresults);
print Dumper($data);
chdir('..');
}
}
ERROR
music/gitar/education.xml
File does not exist: ./music/gitar/education.xml
答案 0 :(得分:1)
使用chdir
的方式使得代码IMO的可读性降低。您可以使用File::Find:
use autodie;
use File::Find;
use XML::Simple;
use Data::Dumper;
sub findxml {
my @found;
opendir(DIR, '.');
my @where = grep { -d && m#^[^.]+$# } readdir(DIR);
closedir(DIR);
File::Find::find({wanted => sub {
push @found, $File::Find::name if m#^education\.xml$#s && -f _;
} }, @where);
return @found;
}
foreach my $xml (findxml()){
say $xml;
print Dumper XMLin($xml);
}
答案 1 :(得分:0)
每当你发现自己依赖反引号来执行shell命令时,你应该考虑是否有适当的perl方法来执行它。在这种情况下,有。
ls
可以替换为<*>
,这是一个简单的glob。这一行:
my @array = map { chomp; $_ } `ls`;
只是一种迂回的说法
chomp(my @array = `ls`); # chomp takes list arguments as well
但当然正确的方法是
my @array = <*>; # no chomp required
现在,所有这一切的简单解决方案就是
for my $xml (<*/education.xml>) { # find the xml files in dir 1 level up
这将涵盖一级目录,没有递归。要进行完全递归,请使用File::Find
:
use strict;
use warnings;
use File::Find;
my @list;
find( sub { push @list, $File::Find::name if /^education\.xml$/i; }, ".");
for (@list) {
# do stuff
# @list contains full path names of education.xml files found in subdirs
# e.g. ./music/gitar/education.xml
}
您应该注意,不需要更改目录,根据我的经验,不值得麻烦。而不是做:
chdir($somedir);
my $data = XMLin($somefile);
chdir("..");
简单地说:
my $data = XMLin("$somedir/$somefile");