2016-04-29 31 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);