Parse XML data and append a new element using XML::Simple

不打扰是莪最后的温柔 提交于 2019-12-25 18:26:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!