使用 xml 文件中的 perl 更改一行並刪除標籤?
我有一個 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
。我只是想完成這項工作,最簡單的方法對我有用。我將只有我提到的上述兩件事的一個實例。
以此作為範例輸入文件:
$ 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;'