Разбор XML — вычитание значений из тегов

У меня есть следующая структура xml в очень большом файле:

<sit>619709.6044;144998.7059;-090372.58119</sit>
<vll>0;0;0</vll>
<cor>255;0;255</cor>

Как вычесть значения в теге sit? Тег состоит из трех значений, разделенных знаком ; Каждое значение необходимо вычесть из определенного числа.

Можно использовать любой инструмент unix. (awk, sed, bc и т. д.)

Итак, если это конкретное число равно 1000 для первого значения, 100 для второго значения и 10 для третьего значения, результат будет таким:

<sit>618709;144898;-090362</sit>
<vll>0;0;0</vll>
<cor>255;0;255</cor>

Не нужно сохранять дроби.


person John Mac    schedule 08.02.2013    source источник


Ответы (2)


Вот один из способов использования awk. Беги как:

awk -v a=1000 -v b=100 -v c=10 -F "[<;>]" -v OFS=";" -f ./script.awk file

Содержание script.awk:

/^<sit>/ && /<\/sit>$/ {
    $0 = "<sit>" format($3, a) OFS format($4, b) OFS format($5, c) "</sit>"
}1

function format(field, var) {
    f = sub(/^-/, "", field)
    return (f == 1 ? "-" : "") sprintf("%06d", int(field-var))
}

Полученные результаты:

<sit>618709;144898;-090362</sit>
<vll>0;0;0</vll>
<cor>255;0;255</cor>

Вы не совсем поняли, как форматировать вывод. Похоже, вы хотите, чтобы ваши целые числа были дополнены до шести ведущих нулей, независимо от того, положительные они или отрицательные. Приведенный выше скрипт сделает это. Если этот ноль на самом деле опечатка, то этой строчки должно быть достаточно:

awk -v a=1000 -v b=100 -v c=10 -F "[<;>]" -v OFS=";" '/^<sit>/ && /<\/sit>$/ { $0 = "<sit>" sprintf("%06d",int($3-a)) OFS sprintf("%06d",int($4-b)) OFS sprintf("%06d",int($5-c)) "</sit>" }1' file

Полученные результаты:

<sit>618709;144898;-90382</sit>
<vll>0;0;0</vll>
<cor>255;0;255</cor>
person Steve    schedule 09.02.2013
comment
Именно то, что я хотел... набивка. Извините за мой слабый кунгфэнглиш. - person John Mac; 13.02.2013

Один из способов использования perl с помощью парсера XML::Twig:

Предполагая xmlfile со следующими данными:

<root>
        <sit>619709.6044;144998.7059;-090372.58119</sit>
        <vll>0;0;0</vll>
        <cor>255;0;255</cor>
</root>

и код script.pl:

#!/usr/bin/env perl

use warnings;
use strict;
use XML::Twig;
use POSIX qw<floor ceil>;

my @substracts = qw<1000 100 10>;

my $twig = XML::Twig->new(
    twig_handlers => {
        'sit' => sub { 
            my @sit_values = map { $_ < 0 ? ceil $_ : floor $_  } split /;/, $_->text_only;
            for my $i ( 0 .. $#substracts ) { 
                $sit_values[ $i ] -= $substracts[ $i ];
            }   

            $_->set_text( join q|;|, @sit_values );
        }   
    },  
    pretty_print => 'indented',
)->parsefile( shift )->print;

Запустите его как:

perl-5.14.2 script.pl xmlfile

Это дает:

<root>
  <sit>618709;144898;-90382</sit>
  <vll>0;0;0</vll>
  <cor>255;0;255</cor>
</root>
person Birei    schedule 08.02.2013