2009-01-15 6 views
5

Ich habe eine XML-Datei mit der folgenden Zeile:Wie kann ich mit awk oder Perl eine Zahl in einer großen XML-Datei erhöhen?

  <VALUE DECIMAL_VALUE="0.2725" UNIT_TYPE="percent"/> 

Ich mag würde diesen Wert von .04 und hielt das Format der XML in Position zu erhöhen. Ich weiß, dass dies mit einem Perl- oder awk-Skript möglich ist, aber ich habe Schwierigkeiten mit den Ausdrücken, um die Nummer zu isolieren.

Antwort

4

Wenn Sie auf einem Feld mit dem xsltproc Befehl an Ort und Stelle sind würde ich Sie XSLT vorschlagen für diese.

Für eine Perl-Lösung würde ich für die Verwendung des DOM gehen. Überprüfen Sie diesen Artikel DOM Processing with Perl Artikel aus.

Das sagte. Wenn Ihre XML-Datei in vorhersehbarer Weise etwas naiv wie die folgende erzeugt wird funktionieren könnte:

perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;' 
+0

Ich denke du meinst "($ 2 + 0,4)" nicht "(2 $ * 0,4)". –

+0

Ja, dumm mich. Ich werde das sofort beheben. – PEZ

0

Etwas ähnlich wie folgt funktioniert. Es muss möglicherweise optimiert werden, wenn es zusätzlichen Abstand gibt, aber das ist eine Übung für den Leser.

function update_after(in_string, locate_string, delta) { 
    local_pos = index(in_string,locate_string); 
    leadin = substr(in_string,0,local_pos-1); 
    leadout = substr(in_string,local_pos+length(locate_string)); 
    new_value = leadout+delta; 
    quote_pos = index(leadout,"\""); 
    leadout = substr(leadout, quote_pos + 1); 
    return leadin locate_string new_value"\"" leadout; 
} 

/^ *\<VALUE/{ 
    print update_after($0, "DECIMAL_VALUE=\"",0.4); 
} 
2

Dieser nimmt die Eingabe auf stdin, zu den Ausgängen stdout:

while(<>){ 
if($_ =~ /^(.*DECIMAL_VALUE=\")(.*)(\".*)$/){ 
    $newVal = $2 + 0.04; 
    print "$1$newVal$3\n"; 
}else{ 
    print $_; 
} 
} 
3

Wenn Sie absolut sicher sind, dass das Format von Ihrem XML wird sich nie ändern, dass die Reihenfolge der Attribute festgelegt ist, dass Sie tatsächlich die Regexp für die Zahl richtig bekommen können ... dann gehen Sie für die Nicht-Parser-basierte Lösung.

Persönlich würde ich XML :: Twig verwenden (vielleicht weil ich es geschrieben habe; -). Es verarbeitet das XML als XML, wobei das ursprüngliche Format der Datei berücksichtigt wird. Es wird nicht vollständig in den Arbeitsspeicher geladen, bevor mit der Arbeit begonnen wird.

Ungeprüfte Code unten:

#!/usr/bin/perl 
use strict; 
use warnings; 

use XML::Twig; 

XML::Twig->new(# call the sub for each VALUE element with a DECIMAL_VALUE attribute 
       twig_roots => { 'VALUE[@DECIMAL_VALUE]' => \&upd_decimal }, 
       # print anything else as is 
       twig_print_outside_roots => 1, 
      ) 
     ->parsefile_inplace('foo.xml'); 

sub upd_decimal 
    { my($twig, $value)= @_; # twig is the XML::Twig object, $value the element 
    my $decimal_value= $value->att('DECIMAL_VALUE'); 
    $decimal_value += 0.4; 
    $value->set_att(DECIMAL_VALUE => $decimal_value); 
    $value->print; 
    } 
+0

Hey, ich habe in Projekten gearbeitet, die stark auf Twig basieren. Verspäteter Dank für das Schreiben eines so hervorragenden Moduls! – PEZ

+0

Thanks.I womder wenn XML :: Twig XSLT ist, was Perl zu LISP ist (siehe http://xkcd.com/224/) – mirod

+0

Könnte sein. Könnte sein. =) – PEZ

0

hier die gaffen

awk '/DECIMAL_VALUE/{ 
for(i=1;i<=NF;i++){ 
    if($i~/DECIMAL_VALUE/){ 
     gsub(/DECIMAL_VALUE=|\042/,"",$i) 
     $i="DECIMAL_VALUE=\042"$i+0.4"\042" 
    } 
} 
}1' file 
Verwandte Themen