Удалить строки из XML-файла, если содержит те же слова (Perl) - PullRequest
0 голосов
/ 13 января 2012

У меня есть файл "sizes.xml", который содержит строки с этой формой:

<?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: $!";

Ответы [ 5 ]

3 голосов
/ 13 января 2012

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

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

обновление :

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

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;
0 голосов
/ 13 января 2012

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

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

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

0 голосов
/ 13 января 2012
$ perl -pi.tmp -ale '$_="" if $seen{ $F[2] }++' frequencies.xml
0 голосов
/ 13 января 2012
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 голосов
/ 13 января 2012

В одну сторону, используя однострочный скрипт:

perl -ne '($freq) = m/(?i)channel="([^"]+)/; print unless exists $arr{ $freq }; $arr{ $freq } = 1' infile
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...