Как я могу использовать awk или Perl для увеличения числа в большом XML-файле? - PullRequest
5 голосов
/ 15 января 2009

У меня есть XML-файл со следующей строкой:

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

Я хотел бы увеличить это значение на 0,04 и сохранить формат XML на месте. Я знаю, что это возможно с помощью сценария Perl или awk, но у меня возникают трудности с выражениями для выделения числа.

Ответы [ 5 ]

4 голосов
/ 15 января 2009

Если вы используете коробку с командой xsltproc, я бы предложил вам использовать XSLT для этого.

Для решения Perl я бы пошел на использование DOM. Проверьте это DOM Обработка с Perl статья вне.

Это сказал. Если ваш XML-файл создан предсказуемым образом, может сработать что-то наивное, например, следующее:

perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;'
3 голосов
/ 16 января 2009

Если вы абсолютно уверены, что формат вашего XML никогда не изменится, что порядок атрибутов фиксирован, что вы действительно можете получить регулярное выражение для правильного числа ... тогда перейдите к решению, не основанному на парсере ,

Лично я бы использовал XML :: Twig (возможно, потому что я написал это; -). Он будет обрабатывать XML как XML, сохраняя при этом исходный формат файла, и не будет загружать все это в память перед началом работы.

Непроверенный код ниже:

#!/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;
  }
2 голосов
/ 15 января 2009

Это принимает ввод на стандартный вывод, выводит на стандартный вывод:

while(<>){
 if( $_ =~ /^(.*DECIMAL_VALUE=\")(.*)(\".*)$/ ){
  $newVal = $2 + 0.04;
  print "$1$newVal$3\n";
 }else{
  print $_;
 }
}
0 голосов
/ 25 ноября 2009

вот зевака

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
0 голосов
/ 15 января 2009

Что-то похожее на следующее будет работать. Может потребоваться настройка, если есть дополнительное расстояние, но это оставлено в качестве упражнения для читателя.

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...