Linux

使用 xml 文件中的 perl 更改一行並刪除標籤?

  • September 21, 2015

我有一個 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_id23$wordabc

我只是想完成這項工作,最簡單的方法對我有用。我將只有我提到的上述兩件事的一個實例。

以此作為範例輸入文件:

$ 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

請 - 不要使用正則表達式來解析 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;'

引用自:https://unix.stackexchange.com/questions/230207