我想为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),纯字符串操作。
答案 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 }
。
我更新了正则表达式以处理修改后的输入。一旦你在一行上有多个开放标签,它就会失败。