使用脚本为xml中的每个标记添加递增值属性

时间:2010-08-31 06:48:53

标签: xml perl shell sed awk

我想为xml中的每个标记添加一个属性,该标记使用awk,sed,perl或plain shell cmd递增

例如:

<tag1 key="123">
  <tag2 abc="xf d"/>
  <tag3 def="d2 32">
   </tag3>
</tag1>

我期待以下输出

<tag1 key="123" order="1">
  <tag2 abc="xf d" order="2"/>
  <tag3 def="d2 32" order="3">
   </tag3>
</tag1>

如果可能的话,我不会查看任何依赖项(Twig,LibXML),纯字符串操作。

3 个答案:

答案 0 :(得分:4)

我喜欢Perl的XML::Twig这类事情。你必须根据你正在做的任何事情调整它,这样你就可以访问你想要影响的所有元素。要在孩子面前处理父母,队列可能就是你想要的:

use XML::Twig;

my $xml = <<'XML';
<tag1 key="123">
  <tag2 key="1234"/>
  <tag3 key="12345">
   </tag3>
</tag1>
XML

my $twig = XML::Twig->new(
    pretty_print => 'indented',
    );
$twig->parse( $xml );
my @queue = ( $twig->root );

my $n = 1;  
while( my $elem = shift @queue ) {
    next unless $elem->tag =~ /\Atag[123]\z/;
    $elem->set_att( order => $n++ );
    push @queue, $elem->children( qr/\Atag/ );
    }

$twig->print;

此脚本的输出为:

<tag1 key="123" order="1">
  <tag2 key="1234" order="2"/>
  <tag3 key="12345" order="3"></tag3>
</tag1>

答案 1 :(得分:2)

使用XML :: LibXML和一滴XPath非常简单。

#!/usr/bin/perl

use strict;
use warnings;

use XML::LibXML;

my $counter = 1;

my $xp = XML::LibXML->new->parse_file('test.xml');

foreach($xp->findnodes('//*')) { # '//*' returns all nodes
  $_->setAttribute('order', $counter++);
}

print $xp->toString;

答案 2 :(得分:-1)

通常你应该使用适当的解析器来处理xml。但在awk

awk 'match($0, /<[^\/>]+/) { \
     $0 = substr($0, 1, RSTART+RLENGTH-1) " order=\"" ++i "\"" \
          substr($0, RSTART+RLENGTH) \
     }; 1'

我在每一行都找到一个开头标记(没有>/>部分)。如果找到,请将字符串order="i"放在其后,同时递增i。最后一行的单1始终执行awk的默认操作:{ print $0 }

我更新了正则表达式以处理修改后的输入。一旦你在一行上有多个开放标签,它就会失败。