我有一个 xml 文件(client_23.xml)
,需要在其中更改一行并从中删除整个标记,因此我想出了 perl 脚本:
在我的 xml 文件中,我有一个这样的块。<hello>collect_model = 1</hello>
我的 xml 文件中只有一个实例:
<world>
<hello>collect_model = 1</hello>
<hello>enable_data = 0</hello>
<hello>session_ms = 2*60*1000</hello>
<hello>max_collect = string_integer($extract("max_collect"))</hello>
<hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
<hello>output('{')</hello>
</world>
我需要将该行更改为这样:<hello>collect_model = 0</hello>
所以更改后我的整个块应该是这样的:
<world>
<hello>collect_model = 0</hello>
<hello>enable_data = 0</hello>
<hello>session_ms = 2*60*1000</hello>
<hello>max_collect = string_integer($extract("max_collect"))</hello>
<hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
<hello>output('{')</hello>
</world>
第二件事是我需要从同一个 xml 文件中删除整个标签:
<derta-config>
<data-users>2000</data-users>
<test-users>2000</test-users>
<attributes>hello world</attributes>
<client-types>Client1</model-types>
<target>price.world</target>
</derta-config>
所以我有下面的shell脚本,我在其中使用perl,它尝试做以上两件事,同时替换文件中的一些内容(我这样做是为了其他目的),但我专门为上面两件事添加的部分并没有工作并开始打印一堆错误:
perl -0pe "s#<eval>collect_model = 0</eval>#<eval>collect_model = 1</eval> s#<derta-config>.* </derta-config>##sm; s#<function>\s*<name>DUMMY_FUNCTION.+?</function>#$file#sm" client_"$client_id".xml > "$word"_new_file.xml
所以我在想,我们是否可以在 shell 脚本中执行此操作,这意味着使用 shell 脚本删除上述两件事,然后将其输出传递给正在第三步工作的 perl 脚本。那么我们可以将 shell 脚本的输出传递给下面的 perl 脚本,这将为我删除上述两件事吗?这可以吗?
perl -0pe "s#<function>\s*<name>DUMMY_FUNCTION.+?</function>#$file#sm" client_"$client_id".xml > "$word"_dyn_model.xml
这里$client_id
是,23
也是。$word
abc
我只是想让这项工作成功,无论什么最简单的方法都会对我有用。我只举一个我提到的上述两件事的例子。
答案1
请不要使用正则表达式来解析 XML。这是一个坏主意。这是一个坏主意的主要原因是 XML 的种类繁多,并且一些语义相同的 XML 可能具有一些显着不同的模式匹配。
考虑换行符、空格、一元标签等。
<element />
<element></element>
两者是相同的 - 然后你可以缩进、换行、分割标签等:
<element
att1="fish"
att2="carrot">
亦有效。
所以我会强烈地建议“使用解析器”。 Perl 有多种选择 - 我喜欢XML::Twig
:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( \*DATA );
foreach my $hello ( $twig->findnodes('//hello') ) {
if ( $hello->trimmed_text =~ m/collect_model/ ) {
$hello->set_text('collect_model = 0');
}
}
$_->delete for $twig->findnodes('//derta-config');
$twig->print;
__DATA__
<root>
<world>
<hello>collect_model = 1</hello>
<hello>enable_data = 0</hello>
<hello>session_ms = 2*60*1000</hello>
<hello>max_collect = string_integer($extract("max_collect"))</hello>
<hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
<hello>output('{')</hello>
</world>
<derta-config>
<data-users>2000</data-users>
<test-users>2000</test-users>
<attributes>hello world</attributes>
<client-types>Client1</client-types>
<target>price.world</target>
</derta-config>
</root>
因为你似乎喜欢 perl 中的一行:
perl -MXML::Twig -0777 -e 'my $twig = XML::Twig->parse (<>); $_->set_text("collect_model = 0") for grep { $_->text =~ m/collect_model/ } $twig->findnodes("//hello"); $_->delete for $twig->findnodes("//derta-config"); $twig -> print;'
答案2
以此作为示例输入文件:
$ cat client_23.xml
<world>
<hello>collect_model = 1</hello>
<hello>enable_data = 0</hello>
<hello>session_ms = 2*60*1000</hello>
<hello>max_collect = string_integer($extract("max_collect"))</hello>
<hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
<hello>output('{')</hello>
</world>
<derta-config>
<data-users>2000</data-users>
<test-users>2000</test-users>
<attributes>hello world</attributes>
<client-types>Client1</model-types>
<target>price.world</target>
</derta-config>
我们可以使用以下方法进行这两项更改:
$ sed 's|<hello>collect_model = 1</hello>|<hello>collect_model = 0</hello>|; \|<derta-config>|,\|</derta-config>|d' client_23.xml
<world>
<hello>collect_model = 0</hello>
<hello>enable_data = 0</hello>
<hello>session_ms = 2*60*1000</hello>
<hello>max_collect = string_integer($extract("max_collect"))</hello>
<hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
<hello>output('{')</hello>
</world>
怎么运行的
我们有两个 sed 命令。第一个是替换,第二个是删除:
s|<hello>collect_model = 1</hello>|<hello>collect_model = 0</hello>|
替代命令的形式为
s|old|new|
.所以,这old
是原来的<hello>collect_model = 1</hello>
,new
是替换的<hello>collect_model = 0</hello>
。\|<derta-config>|,\|</derta-config>|d
这定义了一系列行。起始行包含
derta-config>
,结束行包含</derta-config>
。该范围内的所有行都将被删除命令删除d
。