2015-10-20 146 views
-3

data.xml中Perl中,刪除XML節點

<people> 
    <person name="John"> 
    <param name="age" value="21" /> 
    </person> 
    <person name="Jane"> 
    <param name="age" value="25" /> 
    </person> 
</people> 

我有這個片XML的。我正在編寫腳本以將<person>節點附加到<people>節點。我正在使用XML :: Simple

(請不要建議我使用另一個庫,我知道它的困難)。

my $remove_person = "Jane"; 

my $xml = XMLin('data.xml', ForceArray => 1, KeepRoot => 1, KeyAttr => []); 
if(exists $xml->{people}[0]{person}){ 
     my $var = $xml->{people}[0]{person}; 
     my $count = @$var; 
     my $person_index = 0; 
     for(my $i = 0; $i < $count; $i++){ 
       if($xml->{people}[0]{person}[$i]->{name} eq $remove_person){ 
         print "Person found at " . $person_index . " index"; 
         $person_index = $i; 
         $person_to_remove = $xml->{people}[0]{person}[$i]; 
       } 
     } 
} else { 
     print "Person not found in data.xml\r"; 
} 

上面一段代碼給我我要刪除的節點的索引。 它從這一點,我有我的麻煩。我無法找到從數據中刪除此索引的正確方法。
到目前爲止,我已經嘗試過一種使用splice的方法,它返回了我想要刪除的XML部分,然後我使用XMLout()將該數組轉換回XML。使用=~ s///g,我能夠編輯節點更改(<person>成爲<opt>)。一旦我想XMLout()'ed原來的data.xml結構,我試圖用原始結構的空字符串替換XML的可移動部分的變量。

顯然,這沒有奏效。

​​

如何我會刪除XML的這一部分,或者通過陣列數據刪除,或純文本文件清除,以寫回原來的data.xml文件的新結構?

回答

0

正如你已經被toldXML::Simple的一點是,而不是使用字符串處理Perl數據結構。所以,忘記s///並嘗試

my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1); 
my $remove = 'Jane'; 
delete $xml->{people}[0]{person}{$remove}; 
print XMLout($xml, KeepRoot => 1); 

,或者空KeyAttr

my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1, KeyAttr => []); 
@{ $xml->{people}[0]{person} } = grep $_->{name} ne $remove, 
           @{ $xml->{people}[0]{person} }; 
print XMLout($xml, KeepRoot => 1); 

爲了比較,相同的任務在XML::XSH2

open data.xml ; 
my $remove = 'Jane' ; 
delete /people/person[@name=$remove] ; 
save :b ; 
+0

刪除功能,建議不要使用(具有諷刺意味的在我的情況下,其在石頭上所寫的,我使用::簡單)。我的問題的最終產品是一個電話系統腳本,沒有,系統無法運行。如果提供了正確的索引檢查,我是否可以假設使用delete不會導致perl文檔中警告的任何'意外行爲'? (我已經對:: Simple有足夠的難度,所以我寧願減少任何額外的難度/風險) –

+1

@Simon。 'delete'不應該用於數組。我用它來做一個好的散列。 – choroba

1

編輯:下面是張貼之前'請不要建議我使用其他圖書館'被添加到問題。我要離開它,因爲我仍然認爲正確的答案是「不要使用XML::Simple」。你可以用錘子把螺絲釘放在牆上,但不會改變這個事實,無論你用力如何,結果都會變得混亂。

不要使用XML::Simple,這很容易。即使XML::Simple說:

該模塊在新代碼中的使用是不鼓勵的。其他模塊可提供更直接和一致的接口。

最根本的問題是隻有微不足道(簡單!)的XML可以通過散列和數組直接表示。如果你仔細想想--XML允許在同一個父代下面有重複的節點,但是具有不同的屬性和內容。它也允許一元標籤。

如何使用XML::Twig代替:

#!/urs/bin/env perl 
use strict; 
use warnings; 

use XML::Twig; 

my $twig = XML::Twig -> new ('pretty_print' => 'indented_a') -> parsefile ('your_xml'); 
foreach my $element ($twig -> get_xpath('person[@name="Jane"]')) { 
    $element -> delete; 
} 

$twig -> print; 

你可以 - 如果需要 - 也可以通過使用parsefile_inplace就地編輯做到這一點。否則,請打開一個新文件並通過$twig -> sprint輸出新的XML。

例如:

XML::Twig->new(
    'pretty_print' => 'indented_a', 
    'twig_handlers' => { 
     'person[@name="Jane"]' => sub { $_->delete } 
    } 
)->parsefile_inplace('xml_filename.xml'); 

如果你在使用錘子你螺絲的意圖 - 這應該與您最初的代碼和XML::Simple做到這一點:

$xml->{people}[0]{person} = 
    [ grep { not $_->{name} eq $remove_person } 
         @{ $xml->{people}[0]{person} } ]; 

替換有問題的陣列上的濾波陣列name屬性。

輸出:

<people> 
    <person name="John"> 
    <param name="age" value="21" /> 
    </person> 
</people> 
0

可悲的是我在roughtly同樣的問題結束了,我必須在AIX上編輯一些XML而無需額外的庫。我結束了刪除像這樣的東西

perl -0777 -p -i -e "s;(<HARDWARE>.*)<DESCRIPTION>.*<\/DESCRIPTION>(.*<\/HARDWARE>);\$1\$2;s" my.xml 

這是醜陋的。我不喜歡它。但它的工作,然後讓你知道如何寫一個現在應該做的正則表達式。