使用正则表达式处理 XML 有很多陷阱。
也就是说,下面是一种快速而肮脏的方法。它使用多个零宽度前瞻断言
(?=...)
。第一个按照优先顺序寻找替代方案,首先命名,然后返回路径。他们使用特殊的哈希 %+
来获取命名捕获组中的值,例如、(?<revision>...)
。
我在上面提到了陷阱。例如,请注意带引号的恶作剧。
#! /usr/bin/env perl
use strict;
use warnings;
while (<>) {
if (/(?=.*\b(?<name>name\s*=\s*["'].*?["'])|(?<path>path\s*=\s*["'].*?["']))
(?=.*\b(?<revision>revision\s*=\s*["'].*?["']))/x)
{
if (exists $+{path} && exists $+{revision}) {
print $+{path}, " , ", $+{revision}, "\n";
}
elsif (exists $+{name} && exists $+{revision}) {
print $+{name}, " , ", $+{revision}, "\n";
}
else {
chomp;
warn "$_\n - must have name or path and revision\n";
}
}
}
正确的方法是使用解析器。
#! /usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
while (<>) {
my $dom = XML::LibXML::->load_xml(string => $_);
foreach my $project ($dom->findnodes('/project | /Project')) {
if (exists $project->{name} && exists $project->{revision}) {
print qq[name="$project->{name}" , revision="$project->{revision}"\n];
}
elsif (exists $project->{path} && exists $project->{revision}) {
print qq[name="$project->{path}" , revision="$project->{revision}"\n];
}
else {
warn "$0: $ARGV:$.: must have name or path and revision attributes\n";
}
}
}
将任一程序保存到
namerev
,然后运行它
perl namerev input-file.xml
产生下面的输出。
name="kernel/lk" , revision="e48c9314142c2ae93619ccd14aba2bc975165ffd"
name="device/google/contexthub" , revision="c453c8b8fb25fb8e1c59e8288331a70dbff44061"
if ($row =~ m/name="(.+?)"\spath="(.+?)"\srevision="(.+?)"/g) { 打印“$1 $3 “;
test
}enter code here
elsif ($row =~ m/name="(.+?)"\srevision="(.+?)"/g)
{test
打印“$1$2
”;
}
}test