次の行のXMLファイルがあります。
<VALUE DECIMAL_VALUE="0.2725" UNIT_TYPE="percent"/>
この値を.04ずつ増やし、XMLの形式を維持したいと思います。これはPerlまたはawkスクリプトで可能であることは知っていますが、数値を分離する式に問題があります。
xsltproc コマンドが配置されているボックスを使用している場合は、これに XSLT を使用することをお勧めします。
Perl ソリューションの場合は、DOM を使用します。このDOM Processing with Perlの記事をチェックしてください。
それは言った。XML ファイルが予測可能な方法で作成された場合、次のような素朴な方法でうまくいく可能性があります。
perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;'
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;
}
これは、stdinに入力を受け取り、stdoutに出力します。
while(<>){
if( $_ =~ /^(.*DECIMAL_VALUE=\")(.*)(\".*)$/ ){
$newVal = $2 + 0.04;
print "$1$newVal$3\n";
}else{
print $_;
}
}
次のようなものが機能します。余分な間隔がある場合は微調整が必要になる場合がありますが、それは読者の練習問題として残されています。
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);
}
ここがガウク
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