使用 perl 从 xml 文件中更改行并删除标签?

使用 perl 从 xml 文件中更改行并删除标签?

我有一个 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也是。$wordabc

我只是想让这项工作成功,无论什么最简单的方法都会对我有用。我只举一个我提到的上述两件事的例子。

答案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

相关内容