2012-01-13 2 views
0

У меня есть файл «frequencies.xml», который содержит строки с этой формой:Удалить строки из XML-файла, если содержит же слова (Perl)

<?xml version="1.0"?> 
<!DOCTYPE stationlist PUBLIC "-//xxxxx//DTD stationlist 1.0//EN" "http://xxxxxxxxx/DTD/xxxxxxxx.dtd"> 
<frequencies xmlns="http://xxxxxxxxxxxxxxxx/DTD/"> 
<list norm="PAL" frequencies="Custom" audio="bg"> 
.............................................................. 
<station name="A" active="1" channel="48.25MHz" norm="PAL"/> 
<station name="B" active="1" channel="55.25MHz" norm="PAL"/> 
<station name="C" active="1" channel="62.25MHz" norm="PAL"/> 
<station name="D" active="1" channel="112.25MHz" norm="PAL"/> 
.............................................................. 
<station name="E" active="1" channel="119.25MHz" norm="PAL"/> 
<station name="F" active="0" channel="48.25MHz" norm="PAL"/> 
.............................................................. 
<station name="G" active="1" channel="55.25MHz" norm="PAL"/> 
<station name="H" active="0" channel="62.25MHz" norm="PAL"/> 
.............................................................. 
    </list> 
</frequencies> 

Я хочу, чтобы удалить строки считается дубликата, если содержит одни и те же частоты с другой линия.

Вывод результатов:

<station name="A" active="1" channel="48.25MHz" norm="PAL"/> 
<station name="B" active="1" channel="55.25MHz" norm="PAL"/> 
<station name="C" active="1" channel="62.25MHz" norm="PAL"/> 
<station name="D" active="1" channel="112.25MHz" norm="PAL"/> 
<station name="E" active="1" channel="119.25MHz" norm="PAL"/> 

Я пишу сценарий, чтобы сделать это:

for i in `cat frequencies.xml | sed 's/.*channel="\([^"]*\)".*/\1/; /</ d' |grep MHz`; do 
cat frequencies.xml | awk -v i="channel=\"$i" ' 
    BEGIN  { a=0 } 
    $0 ~ i  { if (a == "1") { print i"\" - duplicate" > "/dev/stderr" ; next ;} ; a=1 } 
      { print $_ }' > frequencies.xml.tmp && \ 
mv frequencies.xml.tmp frequencies.xml 
done 

Как перенося это на языке Perl?

Благодаря

Обновление: Я хочу, чтобы сохранить структуру XML.

Мой код:

open (FH, "+< frequencies.xml") or die "Opening: $!"; 
my $out = ''; 
my %seen =(); 
foreach my $line (<FH>) { 
    if ($line =~ m/<station/) { 
     my ($freq) = ($line =~ m/channel="([^"]+)"/); 
      $out .= $line unless $seen{$freq}++; 
    } else { 
     $out .= $line; 
    } 
} 
seek(FH,0,0)     or die "Seeking: $!"; 
print FH $out     or die "Printing: $!"; 
truncate(FH, tell(FH))   or die "Truncating: $!"; 
close(FH)      or die "Closing: $!"; 

ответ

3

Держите хэш, чтобы отслеживать, какие частоты вы уже видели, и если вы видели его, не выделяют строку:

обновление:

Если у вас есть другие линии, вам просто нужно их распечатать. Самый простой способ, скорее всего, просто выполнить тест, если это элемент <station>, и распечатать все остальное ... но как только вы начнете усложняться, вы можете использовать один из истинных XML Parsers. Таким образом, используя предложение Заид в:

open INPUT, '<', 'frequencies.xml' or die "Can't read file : $!"; 
my %seen =(); 
foreach my $line (<INPUT>) { 
    if ($line =~ m/<station/) { 
     my ($freq) = ($line =~ m/channel="([^"]+)"/); 
     print $line unless $seen{$freq}++; 
    } else { 
     print $line; 
    } 
} 
close INPUT; 
+1

Это нормально работает. Спасибо. Но как сделать, чтобы сохранить заголовок XML? – user1148015

+1

'print $ line if $ seen {$ freq} ++;' будет работать тоже – Zaid

0

Один из способов, используя скрипт на одну строку:

perl -ne '($freq) = m/(?i)channel="([^"]+)/; print unless exists $arr{ $freq }; $arr{ $freq } = 1' infile 
0
open(IN, '<', 'frequencies.xml') or die; 
while ($inline = <IN>) { 
    $inline =~ /([\d.]+)MHz/; 
    $freq = $1; 
    push(@out, $inline) unless (grep(/$freq/, @out)); 
} 
print "@out\n"; 
+0

Нет необходимости обратного сбрасывания точки внутри класса символов: '/ ([\ d.] +) MHz /' – pilcrow

0
$ perl -pi.tmp -ale '$_="" if $seen{ $F[2] }++' frequencies.xml 
0

Использование XML :: XSH2:

use XML::XSH2; 
xsh q{ 
    open so-8853324.xml; 
    $ch := hash @channel //station; 
    for { keys %$ch } ls xsh:lookup("ch", .)[1]; 
}; 

Я удалил пространство имен из данных, чтобы упростить код.

Смежные вопросы