2016-04-29 34 views
1

我想用perl更新xml中的屬性。這裏的問題是當我更新xml的屬性時它正在發生,但xml格式正在發生變化.Breaking我的頭,但沒用!perl代碼來更新xml中的屬性而不影響xml格式

任何人都可以請建議我一些Perl代碼了影響XML格式

我用Perl代碼如下所示

#!/usr/bin/perl 
use strict; 
use warnings; 
use XML::Simple; 

my $xml_file = '3.xml'; 

my $xml = XMLin(
$xml_file, 
KeepRoot => 1, 
ForceArray => 1 
); 

$xml->{outer1}->[0]->{inner1}->[1]->{name}->[0]->{first} = 'Shane Bond'; 

XMLout(
    $xml, 
KeepRoot => 1, 
NoAttr => 1, 
OutputFile => $xml_file, 
); 

輸入XML更新XML屬性:

<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
     <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name first = "Shanebond" /> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 

預期產量xml:

<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
     <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name first = "Shane Bond" /> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 

實際輸出XML:

<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
    <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name> 
     <first>Shane Bond</first> 
    </name> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 
+0

[*?爲什麼XML ::簡單 「望而卻步」 *](http://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged) – Borodin

回答

0

有很多方法來剝皮這隻貓。一種是使用XML::LibXML。你的例子看起來像這樣;

use v5.12; 
use warnings; 
use XML::LibXML; 

my $filename = '3.xml' ; 
my $xpath = '//name[contains(@first, "Shane")]' ; 

my $dom = XML::LibXML->load_xml(
    location => $filename 
); 

for my $td ($dom->findnodes($xpath)) { 
    $td->setAttribute("first" , "Shane Bond"); 
} 

say $dom->toString();  # print the updated XML 
$dom->toFile("3.xml.new"); # alterntaively, dump it to a file 

當在上面的文件上運行時,它產生;

<?xml version="1.0"?> 
<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
     <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name first="Shane Bond"/> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 

XPath是一種查詢語言 - 在這種情況下$xpath變量是在文檔中的名稱name,並呼籲first包含字符串Shane屬性的任何節點的請求。另一種方法是將$xpath設置爲//name,循環的第二個迭代將具有正確的節點。

有一個很好的「示例教程」XML::LibXML作者:格蘭特麥克萊恩here。那裏有一點點閱讀應該解決任何類似的問題。

+0

嗨馬蒂,非常感謝你分享上面的代碼,我可以看到控制檯上的預期輸出,但沒有更新所需的XML文件。可以爲xml文件更新提供任何建議。 – kmmmf

+0

嗨馬蒂,它的工作..........! xml文件更新工作正常,併爲後期回覆感到抱歉 – kmmmf

-1

而不是使用XML ::簡單的,逐行讀取內容線完成,你需要更改的屬性值的模式匹配。這不會改變你的XML內容格式。

您可以將此解決方案用於臨時目的。

但這不是一個正確的方法。因爲XML需要藉助XPATH值和Pattern匹配值進行修改。

1

您爲XMLout()設置了NoAttr => 1。所述XML::Simple documentation說:

NoAttr => 1#在+出來 - 得心應手

當與XMLout(使用),將所生成的XML將不包含屬性。 所有散列鍵/值將被表示爲嵌套元素。

與XMLin()一起使用時,XML中的任何屬性都將被忽略。

你想要一個屬性,但關閉屬性?

我嘗試: 打印XMLout( XMLin( 「t.xml」,KeepRoot => 1,ForceArray => 1), KeepRoot => 1 );

兩個文件的差異看起來不錯:

$ diff -bBEup t.xml t2.xml 
--- t.xml 2016-04-29 10:36:28.446578760 +0200 
+++ t2.xml 2016-04-29 10:39:03.450073658 +0200 
@@ -7,7 +7,7 @@ 
    </profession> 
    </inner1> 
    <inner1> 
-  <name first = "Shanebond" /> 
+ <name first="Shanebond" /> 
     <org>newzealand</org> 
     <profession>Shane Bond</profession> 
    </inner1> 

一切正常無NoAttr

$x = XMLin("t.xml", KeepRoot => 1, ForceArray => 1); 
$x->{outer1}->[0]->{inner1}->[1]->{name}->[0]->{first} = "Larry"; 
print XMLout($x, KeepRoot => 1); 

<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
     <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name first="Larry" /> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 
+1

嗨塞巴斯蒂安,其工作非常感謝你..... – kmmmf

0

Why is XML::Simple "Discouraged"?

這其中的道理XML::Simple一個是一個不錯的選擇。

XML::Twig東西可以做這樣的:

#!/usr/bin/perl 
use strict; 
use warnings; 
use XML::Twig; 

my $twig = XML::Twig -> new (pretty_print => 'indented_a'); 
$twig -> parse (\*DATA); 
$twig -> findnodes ('//inner1/name', 1) -> set_att('first', "Shane Bond"); 
$twig -> print; 

__DATA__ 
<outer1> 
    <inner1> 
    <name>Stonecold</name> 
    <org>wwf</org> 
    <profession> 
     <Bowler>hai</Bowler> 
    </profession> 
    </inner1> 
    <inner1> 
    <name first = "Shanebond" /> 
    <org>newzealand</org> 
    <profession>Shane Bond</profession> 
    </inner1> 
    <inner1> 
    <name>brain schemidit</name> 
    <org>Google</org> 
    <profession>Chairman</profession> 
    </inner1> 
</outer1> 

但實際上,我建議,而不是「排序」的節點,你可以使用XPath來查找你想要的:

$twig -> findnodes ('//inner1/name[@first="Shanebond"]', 0) -> set_att('first', "Shane Bond"); 

這不是僅僅選擇'second'元素,而是找到first屬性不正確的地方並修復它。

所以使你的代碼:

#!/usr/bin/perl 
use strict; 
use warnings; 
use XML::Twig; 

my $twig = XML::Twig -> new (pretty_print => 'indented_a'); 
$twig -> parsefile ('3.xml') 
$twig -> findnodes ('//inner1/name[@first="Shanebond"]', 0) -> set_att('first', "Shane Bond"); 

open (my $output, '>', '3.new.xml') or die $!; 
print {$output} $twig -> sprint; 
close ($output);