2017-01-02 36 views
5

我想清除位於目錄樹中的XML文件中的<loot></loot>元素內的整個內容。我正在使用Windows的64位的草莓Perl。使用草莓Perl和樹枝清除Windows上目錄樹中所有文件的xml括號中的內容

例如這個XML文件:

<?xml version="1.0" encoding="UTF-8"?> 
<monster name="Dragon"/> 
<health="10000"/> 
<immunities> 
    <immunity fire="1"/> 
</immunities> 
<loot> 
<item id="1"/> 
    <item id="3"/> 
     <inside> 
     <item id="6"/> 
     </inside> 
    </item> 
</loot> 

更改後的文件應該是:

<?xml version="1.0" encoding="UTF-8"?> 
<monster name="Dragon"/> 
<health="10000"/> 
<immunities> 
    <immunity fire="1"/> 
</immunities> 
<loot> 
</loot> 

我有這樣的代碼:

#!/usr/bin/perl 
use warnings; 
use strict; 

use File::Find::Rule; 
use XML::Twig; 

sub delete_loot { 
    my ($twig, $loot) = @_; 
    foreach my $loot_entry ($loot -> children) { 
     $loot_entry -> delete; 
    } 
    $twig -> flush; 
} 

my $twig = XML::Twig -> new (pretty_print => 'indented', 
           twig_handlers => { 'loot' => \&delete_loot }); 

foreach my $file (File::Find::Rule -> file() 
            -> name ('*.xml') 
            -> in ('C:\Users\PIO\Documents\serv\monsters')) { 

    print "Processing $file\n"; 
    $twig -> parsefile_inplace($file); 
} 

但它正確地編輯只有第一個文件它符合,其餘文件保持清晰(0 kb清除文件)

+0

你可以添加其他文件中,這樣的沒有解決這個問題嗎?你可以[編輯]這個問題。 – simbabque

+0

所有文件都是正確的,但是腳本只在第一個符合的時候才能正常工作,剩下的部分清空了(無論它編輯了哪個xml文件,它只能正確編輯第一個文件) – Piodo

+0

明顯的測試將會 - 循環內有'my $ twig'聲明。 – Sobrique

回答

3

XML::Twig doc表示「多根小枝支撐不好」。

如果看一下樹枝對象的狀態(例如使用Data :: Dumper),您會發現第一次和後續運行之間存在很大差異。看起來它已經被完全刷新了(這是事實,因爲在第一次運行期間已經完全沖洗)。它可能沒有什麼更多的後續文件打印和文件結束爲空。

在每個循環再造樹枝對象爲我工作:

#!/usr/bin/perl 
use warnings; 
use strict; 

use File::Find::Rule; 
use XML::Twig; 

sub delete_loot { 
    my ($twig, $loot) = @_; 
    foreach my $loot_entry ($loot -> children) { 
     $loot_entry -> delete; 
    } 
} 

foreach my $file (File::Find::Rule -> file() 
            -> name ('*.xml') 
            -> in ('/home/dabi/tmp')) { 

    print "Processing $file\n"; 
    my $twig = XML::Twig -> new (pretty_print => 'indented', 
            twig_handlers => { loot => \&delete_loot, }); 
    $twig -> parsefile($file); 
    $twig -> print_to_file($file); 
} 

此外,我不得不改變XML文件結構要把它處理:

<?xml version="1.0" encoding="UTF-8"?> 
<monster name="Dragon"> 
<health value="10000"/> 
<immunities> 
    <immunity fire="1"/> 
</immunities> 
<loot> 
<item id="1"/> 
    <item id="3"> 
     <inside> 
     <item id="6"/> 
     </inside> 
    </item> 
</loot> 
</monster> 
+0

該腳本適用於正確清除戰利品的每個文件,我認爲我們在這裏有一個贏家。不幸的是,10%的xml文件不包含'''''元素。在這種情況下,如果腳本修改沒有''節點的xml怪獸,它將清除該文件(0 kb)。如果沒有'loot'元素,可以放置一個不修改文件的條件,或者在這種情況下不會空白文件? (把空''也可以) – Piodo

+1

確實。這是因爲你在解析時使用flush()。該文檔解釋說:「將一個小枝刷新到(包括)當前元素,然後刪除保存在內存中的所有不必要的元素。」由於沒有掠奪元素的文件不會與你的樹枝處理程序中的任何內容匹配,所以在刷新時你將不會在XML樹中的任何地方。我編輯我的解決方案,以便在解析完成後打印整個樹。如果您同意此解決方案,請讓我知道。 –

+0

謝謝你,這很好。我會盡快給你賞賜我(6小時後) – Piodo

1

注意  與flush更改爲print該問題中的代碼適用於我(使用有效的XML)。

不過,我還是建議以下版本的任一。用兩組有效的XML文件進行測試。


當首先設置XML::Twig->new(...),然後文件循環並處理時,我會得到相同的行爲。第一個文件被正確處理,其他文件完全消隱。   編輯flushprint更換其實作品中所示的代碼(使用正確的XML文件)。不過,我仍然建議下面的任一版本,因爲XML::Twig只是不支持多個文件。

其原因可能有事情做與new是一個類方法。但是,我不明白爲什麼這需要影響處理多個文件。 回調安裝在循環之外,但是我已經針對每個文件重新安裝了該回調進行了測試,但沒有任何幫助。

最後,不需要flush -ing而它清楚地傷害這裏,通過清零狀態(這是由方法new創建)。這不會影響下面的代碼,但它仍被替換爲print

然後只是在循環中做所有事情。一個簡單的版本

use strict; 
use warnings; 
use File::Find::Rule; 
use XML::Twig; 

my @files = File::Find::Rule->file->name('*.xml')->in('...'); 

foreach my $file (@files) 
{ 
    print "Processing $file\n"; 
    my $t = XML::Twig->new( 
     pretty_print => 'indented', 
     twig_handlers => { loot => \&clear_elt }, 
    ); 
    $t->parsefile_inplace($file)->print; 
} 

sub clear_elt { 
    my ($t, $elt) = @_; 
    my $elt_name = $elt->name;    # get the name 
    my $parent = $elt->parent;    # fetch the parent 
    $elt->delete;        # remove altogether 
    $parent->insert_new_elt($elt_name, ''); # add it back empty 
} 

回調代碼被簡化,以完全消除元件,然後將其重新添加,空的。請注意,sub 不需要需要硬編碼的元素名稱。因此可以用它來代替任何元素。

我們可以避免使用另一個類方法nparse在循環中調用new

my $t = XML::Twig->new(pretty_print => 'indented'); 

foreach my $file (@files) 
{ 
    print "Processing $file\n"; 
    my $tobj = XML::Twig->nparse( 
     twig_handlers => { loot => \&clear_elt }, 
     $file 
    ); 
    $tobj->parsefile_inplace($file)->print; 
} 

# the sub clear_elt() same as above 

我們做必須第一次調用new構造,即使它不是在循環直接使用。


請注意,調用new循環之前沒有twig_handlers,然後設置裏面

$t->setTwigHandlers(loot => sub { ... }); 

處理程序沒有幫助。我們仍然只能正確處理第一個文件。

+0

感謝您的回覆。不幸的是,這些腳本會清除所有文件(每個文件,甚至是第一個文件) – Piodo

+1

@Piodo您顯示的XML文件無效,顯示的代碼無法使用,因此您可能使用的文件與所示文件不同。我對它進行了糾正並進行了測試,並且我又編寫了另外兩組XML文件,並對這些文件進行了測試。所示的代碼適用於兩種版本。它也可以和你的子工一起清理'loot'節點。我只是增加了一種不同的方式,因爲它在計算上要簡單得多。 – zdim

+1

@Piodo我也用'print'替換了'flush'。這可能會導致你的問題(它不適用於這兩個版本,但它確實清除了該對象)。 – zdim