我有一个电影收藏目录,其中包含指向文件夹和文件的本地链接,以便于访问。最近我重组了整个硬盘空间,我需要更新链接,我正在尝试用Perl自动完成。
我可以将数据导出到XML文件中并再次导入。我可以使用File::Find来提取新的文件路径,但我遇到了两个问题。我不知道如何将新文件路径中的$title
与XML文件中的相应$title
连接起来。我是第一次处理这些文件,我不知道如何继续更换过程。这是我到目前为止所做的事情
use strict;
use warnings;
use File::Basename;
use File::Find;
use File::Spec;
use XML::Simple;
use Data::Dumper;
my $dir_target = 'D:/Movies/';
my %titles_locations = ();
find(\&file_handler, $dir_target);
sub file_handler {
/\.iso$/ or return;
my $fn = $File::Find::name;
$fn =~ s/\//\\/g;
$fn =~ /(.*\\)(.*)/;
my $path = $1;
my $filename = $2;
my $title = (File::Spec->splitdir($fn))[2];
$title =~ s/(.*?)\s\(\d+\)$/$1/;
$title =~ s/~/:/;
$title =~ s/`/?/;
my $link_local = '<link><description>Folder</description><url>'.$path.'</url><urltype>Movie</urltype></link><link><description>'.$filename.'</description><url>'.$fn.'</url><urltype>Movie</urltype></link>' unless $title eq '';
$titles_locations{$title} = {'filename'=>$filename, 'path'=>$path };
}
my $xml_in = XMLin('somepath/test.xml', ForceArray => 1, KeepRoot => 1);
my $title = {'key1' => 'title', 'key2' => 'links'};
foreach my $link (keys %$title) {
}
print Data::Dumper->Dump([$title]);
my $xml_out = XMLout($xml_in, OutputFile => 'somepath/test_out.xml', KeepRoot=>1);
这是我需要编辑的数据片段。 如果发现imdb和dvdempire链接 - 请勿触摸。 如果找到本地链接替换,否则插入。 我愿意自己完成代码,但需要一些指示如何继续进行。 感谢。
<title>$title</title>
.......
<links>
<link>
<description>IMDB</description>
<url>http://www.imdb.com/title/VARIABLE</url>
<urltype>URL</urltype>
</link>
<link>
<description>DVD Empire</description>
<url>http://www.dvdempire.com/VARIABLE</url>
<urltype>URL</urltype>
</link>
<link>
<description>Folder</description>
<url>OLD_FOLDERPATH</url>
<urltype>Movie</urltype>
</link>
<link>
<description>OLD_FILENAME</description>
<url>OLD_FILENAMEPATH</url>
<urltype>Movie</urltype>
</link>
</links>
答案 0 :(得分:3)
摆脱XML::Simple并使用仅为此类任务而制作的XML::Twig。遍历和元素操作内置于Twig中。当Twig完成大部分工作时,要考虑的事情要少得多。
就将旧路径连接到新路径而言,您拥有的数据并不多。如果它们是相同的文件名但位于不同的文件夹中,那么如果它们是唯一的文件名,则可以是匹配新旧路径的方式。除了获取填充%new_paths
的所有新路径之外,这里的一切都是:
#!perl
use File::Basename qw(basename);
use XML::Twig;
my %new_paths = (
# filename => new_path
...
);
my $twig = XML::Twig->new(
twig_handlers =>
{
link => \&rewrite_link,
},
pretty_print => 'indented',
);
$twig->parse( *DATA );
$twig->flush;
sub rewrite_link
{
my( $link ) = $_;
return unless $link->field( 'urltype' ) eq 'Movie';
# this is from the old file
my $basename = basename( $link->field( 'url' ) );
unless( exists $new_paths{ $basename } )
{
warn "Didn't find a new location for $basename!\n";
return;
}
$link->first_child( 'url' )->set_text( $new_paths{ $basename } );
}
__END__
<titles>
<entry>
<title>$title</title>
<links>
<link>
<description>IMDB</description>
<url>http://www.imdb.com/title/VARIABLE</url>
<urltype>URL</urltype>
</link>
<link>
<description>DVD Empire</description>
<url>http://www.dvdempire.com/VARIABLE</url>
<urltype>URL</urltype>
</link>
<link>
<description>Folder</description>
<url>OLD_FOLDERPATH</url>
<urltype>Movie</urltype>
</link>
<link>
<description>OLD_FILENAME</description>
<url>OLD_FILENAMEPATH</url>
<urltype>Movie</urltype>
</link>
</links>
</entry>
</titles>
答案 1 :(得分:1)
我会提供一个看似合理的方法 - 如果您希望它更充实,请发表评论。
在开头声明哈希my %titles_locations = ();
。
您应该将您的XML处理移出sub a
(请将其称为可读的内容,例如sub file_handler
:)
文件处理程序应该做的是:
像现在一样构建$title
和$link_local
将它们存储在%titles_locations
哈希中,$title
为关键,值为包含{'filename'=>$filename, 'path'=>$path }
现在,在您的代码中,在调用find()
之后,您将调用XMLin。 $xml_in
应该成为一个hashrefs数组(或hashref将你的“root”键映射到一个hashrefs数组。数组中的每个hashref将代表1个标题。
之后,您将遍历标题的arrayref。
arrayref的每个元素(称之为$title
)都是带有2个密钥{hash} "title"
和"links"
的hashref。
从"title"
键的值中,找到%titles_locations
哈希的新路径和文件名。
"links"
键的值将是hashref的一个hashref映射“链接”。我不打算详细说明这里的数据结构,但通过打印Data::Dumper->Dump([$title]);
然后,您将遍历这些链接hashrefs。对于他们每个人(称之为$link
:
$link->{urltype}
ne“电影”,请不要管它(next;
)$link->{description}
eq为“文件夹”,请将$link->{url}
值替换为您从%titles_locations
哈希中找到的新路径。$link->{url}
值替换为您从%titles_locations
哈希中找到的新文件路径。如果$title
不在%titles_locations
散列中,可能会添加一些错误处理。
完成所有循环后,只需将$xml_in
(现在包含更新的信息)转到XMLout()
DONE