问题
I'm using XML::Simple and XML::Dumper. I'm well aware of the issues surrounding the former module. If I could use an alternative library, I would.
What I want to achieve is to load the XML, then append lines to it. This is my XML structure before the script has run.
<person>
<appearance>
<param name="height" value="6,3"/>
</appearence>
</person>
The script, or what I intended to code, should load this XML from a file, then append a <param>
element onto <appearence>
. I've attempted it using this code:
use warnings;
use XML::Simple;
use XML::Dumper;
my $xml = XMLin('xml_import.xml');
$xml->{appearence} .= qq{<param name="age" value="22" />};
my $new_xml = XMLout($xml, noattr => 1, NoEscape => 1);
open(FILE, ">xml_import.xml");
print FILE $new_xml;
close FILE;
Unfortunately the output is this:
<opt>
<appearence>HASH(0x1722190)<param name="age" value="22" /></appearence>
</opt>
Not only do I lose my original <person>
tags to <opt>
but that HASH
string replaces what I assume what was the existing <param>
element. I've read over the documentation for XML::Simple
but I cannot spot what argument should be used to prevent this from happening.
回答1:
The point of using XML::Simple is to use Perl data structures, not XML in your code.
Your problems show exactly why the module is discouraged. You have to use ForceArray
to be able to easily change the number of the elements in a parent, and you have to clear KeyAttr
to block a special handling of the name
attribute.
#!/usr/bin/perl
use warnings;
use strict;
use XML::Simple;
my $xml = << '__XML__';
<person>
<appearance>
<param name="height" value="6,3"/>
</appearance>
</person>
__XML__
my $simple = XMLin($xml, ForceArray => 1,
KeepRoot => 1,
KeyAttr => [],
);
push @{ $simple->{person}[0]{appearance}[0]{param} }, { name => 'age',
value => 22,
};
print XMLout($simple, KeepRoot => 1);
For comparison, the same task in XML::XSH2, a wrapper around XML::LibXML:
open file.xml ;
my $p := insert element param append /person/appearance ;
set $p/@name 'age' ;
set $p/@value 22 ;
save :b ;
回答2:
1.The reason you lose tags is "XMLin() normally discards the root element name. Setting the 'KeepRoot' option to '1' will cause the root element name to be retained."
2.After reading xml from file, should operate the variable as perl data structure.
#! /usr/bin/perl
use strict;
use XML::Simple qw(:strict);
use Data::Dumper;
my $xml = XMLin('xml_import.xml', KeepRoot => 1, KeyAttr => ["param"], ForceArray => ["param"]);
print '-----$xml-----', "\n", Dumper($xml), "\n";
my $new_node = {'name' => 'age', 'value' => '22'};
push $xml->{person}->{appearance}->{param}, $new_node;
print '-----Insert a new node to $xml-----', "\n", Dumper($xml), "\n";
my $new_xml = XMLout($xml, NoAttr => 1, NoEscape => 1, KeepRoot => 1, KeyAttr => []);
print '-----$new_xml-----', "\n", $new_xml, "\n";
Or
#! /usr/bin/perl
use strict;
use XML::Simple qw(:strict);
use Data::Dumper;
my $xml = XMLin('xml_import.xml', KeepRoot => 1, KeyAttr => {param => "+name"}, ForceArray => ["param"]);
print '-----$xml-----', "\n", Dumper($xml), "\n";
my $new_node = {'name' => 'age', 'value' => '22'};
$xml->{person}->{appearance}->{param}->{age} = $new_node;
print '-----Insert a new node to $xml-----', "\n", Dumper($xml), "\n";
my $new_xml = XMLout($xml, NoAttr => 1, NoEscape => 1, KeepRoot => 1, KeyAttr => {param => "+name"});
print '-----$new_xml-----', "\n", $new_xml, "\n";
来源:https://stackoverflow.com/questions/33170323/parse-xml-data-and-append-a-new-element-using-xmlsimple