2012-01-13 1 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のいずれかを使用することができます。だから、ザイドの提案使用して:1行のスクリプトを使用して

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

'$ $ {$ freq} ++;'が使わない限り$行を出力する – Zaid

0

一つの方法:XML :: XSH2使用

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

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

を私は削除しましたコードを単純化するためにデータからの名前空間。