Perl,删除 XML 节点
Perl, Remove XML node
Data.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 的可移动部分的变量与原始结构的空字符串。
显然,这是行不通的。
my $new_xml = XMLout($xml, KeepRoot => 1);
my $remove_xml = XMLout($person_to_remove, KeepRoot => 1);
$remove_xml =~ s/opt/person/g;
$new_xml =~ s/($remove_xml)//g; # facepalm, i know
我如何删除XML的这一部分,通过删除数组数据或删除纯文件文本以便写回原始data.xml 文件的新结构?
编辑:以下内容是在 将“请不要建议我使用其他库”添加到问题之前发布的。我离开它,因为我仍然认为正确答案是 "don't use XML::Simple
"。你可以随心所欲地用锤子在墙上打螺丝,但这并不能改变这样一个事实,无论你用力敲它,结果都会很乱。
不要使用 XML::Simple
这真的很简单。甚至 XML::Simple
说:
The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces.
根本问题是只有微不足道的(简单!)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>
如您所见,, the point of XML::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 ;
遗憾的是,我最终遇到了大致相同的问题,我不得不在 AIX 上编辑一些 XML 而没有额外的库。我最终删除了这样的东西
perl -0777 -p -i -e "s;(<HARDWARE>.*)<DESCRIPTION>.*<\/DESCRIPTION>(.*<\/HARDWARE>);$1$2;s" my.xml
这很丑。我不喜欢它。但它当时有效,前提是您知道如何编写一个时不时应该执行的正则表达式。
Data.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 的可移动部分的变量与原始结构的空字符串。
显然,这是行不通的。
my $new_xml = XMLout($xml, KeepRoot => 1);
my $remove_xml = XMLout($person_to_remove, KeepRoot => 1);
$remove_xml =~ s/opt/person/g;
$new_xml =~ s/($remove_xml)//g; # facepalm, i know
我如何删除XML的这一部分,通过删除数组数据或删除纯文件文本以便写回原始data.xml 文件的新结构?
编辑:以下内容是在 将“请不要建议我使用其他库”添加到问题之前发布的。我离开它,因为我仍然认为正确答案是 "don't use XML::Simple
"。你可以随心所欲地用锤子在墙上打螺丝,但这并不能改变这样一个事实,无论你用力敲它,结果都会很乱。
不要使用 XML::Simple
这真的很简单。甚至 XML::Simple
说:
The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces.
根本问题是只有微不足道的(简单!)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>
如您所见,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 ;
遗憾的是,我最终遇到了大致相同的问题,我不得不在 AIX 上编辑一些 XML 而没有额外的库。我最终删除了这样的东西
perl -0777 -p -i -e "s;(<HARDWARE>.*)<DESCRIPTION>.*<\/DESCRIPTION>(.*<\/HARDWARE>);$1$2;s" my.xml
这很丑。我不喜欢它。但它当时有效,前提是您知道如何编写一个时不时应该执行的正则表达式。