Reputation: 91
I actually asked this question in a different form before. I did get a great answer but I thought I needed more clarifications, so I am asking it in its whole form again.
The user would script something like:
$ABC->Command(100, 100);
my $group = "1";
my $id = "1";
my $value1 = "Some Process A Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group = "1";
my $id = "2";
my $value1 = "Some Process B Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group = "2";
my $id = "1";
my $value1 = "Some Process A Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group = "2";
my $id = "1";
my $value1 = "Some Process Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group = "3";
my $id = "1";
my $value1 = "Some Process Happened";
$rep->getParameter($group, $id, $value1);
$ABC->SomeImage($image) $desc = "Some info";
$rep->getImage($image, $desc);
$rep->getResult("Pass")
This would have to generate an XML like:
<?xml version="1.0" encoding="UTF-8" ?>
<TestResult xmlns="http://test.com/automate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://test.com/automate">
<Result>Pass</Result>
<Comments>Executed Successfully</Comments>
<Parameters>
<ParameterGroup ID="Group1">
<Parameter key="Key1">Some Value</Parameter>
<Parameter key="Key2">Some Value</Parameter>
<Parameter key="Key3">Some Value</Parameter>
</ParameterGroup>
<ParameterGroup ID="Group2">
<Parameter key="Key1">Some Value</Parameter>
<Parameter key="Key2">Some Value</Parameter>
<Parameter key="Key3">Some Value</Parameter>
</ParameterGroup>
<ParameterGroup ID="Group3">
<Parameter key="Key1">Some Value</Parameter>
<Parameter key="Key2">Some Value</Parameter>
<Parameter key="Key3">Some Value</Parameter>
</ParameterGroup>
</Parameters>
<Images>
<Image key="ImageTag1">info</Image>
<Image key="ImageTag2">info</Image>
<Image key="ImageTag3">info</Image>
</Images>
</TestResult>
The image values and parameter values will be input at different points of time. But they would have to be collected and placed inside the Images
element, similarly for Parameters
. What approach should I follow here? Some code samples, please.
edited:
I have something like
$xml = {
ParameterGroup => [
{
ID => 'Group1',
Parameter => {
Key1 => {content => 'Some Value'},
Key2 => {content => 'Some Value'},
Key3 => {content => 'Some Value'},
},
},
{
ID => 'Group2',
Parameter => {
Key1 => {content => 'Some Value'},
Key2 => {content => 'Some Value'},
Key3 => {content => 'Some Value'},
},
},
]
};
print XMLout(
$xml,
RootName => 'Parameters',
KeyAttr => 'value',
);
as the structure but these are fixed structures. How can I make this dynamic to suit the users' requirement?
Upvotes: 1
Views: 611
Reputation: 139411
Consider a few small adjustments below to your driver code.
#! /usr/bin/env perl
use warnings;
use strict;
use TestResult;
my $tr = TestResult->new;
$tr->parameter(1, 1, "Some Process A Happened");
$tr->parameter(1, 2, "Some Process B Happened");
$tr->parameter(2, 1, "Some Process A Happened");
$tr->parameter(3, 1, "Some Process Happened");
$tr->image(1, "Some info");
$tr->result("Pass");
$tr->comments("Executed Successfully");
print $tr->as_xml;
The XML output is
<?xml version="1.0" encoding="UTF-8" ?>
<TestResult xmlns="http://test.com/automate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://test.com/automate">
<Result>Pass</Result>
<Comments>Executed Successfully</Comments>
<Parameters>
<ParameterGroup ID="Group1">
<Parameter key="Key1">Some Process A Happened</Parameter>
<Parameter key="Key2">Some Process B Happened</Parameter>
</ParameterGroup>
<ParameterGroup ID="Group2">
<Parameter key="Key1">Some Process A Happened</Parameter>
</ParameterGroup>
<ParameterGroup ID="Group3">
<Parameter key="Key1">Some Process Happened</Parameter>
</ParameterGroup>
</Parameters>
<Images>
<Image key="ImageTag1">Some info</Image>
</Images>
</TestResult>
Seeing a dump of the contents of $self->{_xml}
may aid your understanding.
{
'Comments' => { 'content' => 'Executed Successfully' },
'Parameters' => {
'ParameterGroup' => {
'Group1' => {
'Parameter' => {
'Key2' => { 'content' => 'Some Process B Happened' },
'Key1' => { 'content' => 'Some Process A Happened' }
}
},
'Group3' => {
'Parameter' => {
'Key1' => { 'content' => 'Some Process Happened' }
}
},
'Group2' => {
'Parameter' => {
'Key1' => { 'content' => 'Some Process A Happened' }
}
}
}
},
'xmlns' => 'http://test.com/automate',
'Result' => { 'content' => 'Pass' },
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation' => 'http://test.com/automate',
'Images' => {
'ImageTag1' => { 'content' => 'Some info' }
}
}
The TestResult module that gets you there is below. Be sure to put it in a file named TestResult.pm
somewhere in the module search path. It begins with familiar boilerplate.
package TestResult;
use strict;
use warnings;
use XML::Simple;
At compile time, we set up a subclass of XML::Simple specific to your desired XML format that will output elements in the appropriate order.
BEGIN {
@__PACKAGE__::XML::ISA = qw/ XML::Simple /;
my %order = (
TestResult => [qw/
xmlns xmlns:xsi xsi:schemaLocation
Result Comments Parameters Images
/],
);
*__PACKAGE__::XML::sorted_keys = sub {
my($self,$name,$h) = @_;
return @{ $order{$name} } if $order{$name};
sort keys %$h;
};
}
Each instance will carry the contents of the output document. The hardcoded key-value pairs become attributes of the TestResult element.
sub new {
my($class) = @_;
my $self = {
_xml => {
"xmlns" => "http://test.com/automate",
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation" => "http://test.com/automate",
},
};
bless $self => $class;
}
The implementations of comments
and result
are simple because the XML they produce is simple. The methods stuff bits in the appropriate slots with no surprises.
sub comments {
my($self,$comments) = @_;
$self->{_xml}{Comments} = { content => $comments };
}
sub result {
my($self,$result) = @_;
$self->{_xml}{Result} = { content => $result };
}
We have to be careful with image
and parameter
because they contain multiple children. Blindly overwriting $self->{_xml}{Images}
or $self->{_xml}{Parameter}
would clobber any content that had already been accumulated, so instead we add new elements incrementally.
sub image {
my($self,$image,$desc) = @_;
my $imageid = "ImageTag" . $image;
$self->{_xml}{Images}{$imageid} = { content => $desc };
}
sub parameter {
my($self,$group,$key,$value) = @_;
my $groupid = "Group" . $group;
my $keyid = "Key" . $key;
$self->{_xml}{Parameters}{ParameterGroup}{$groupid}{Parameter}{$keyid} =
{ content => $value };
}
Finally, we encode the XML using TestResult::XML. The GroupTags
parameter declares nesting relationships, e.g., <Images>
contains <Image>
. (At first, I tried giving similar treatment to the relationships between <Parameters>
and <ParameterGroup>
and between <ParameterGroup>
and <Parameter>
, but the XML output differed from what you want.) The KeyAttr
parameter tells XML::Simple to use Perl hash-keys as XML attributes. The +
prefixes will make for nicer results if you ever use XMLin
to read TestResults generated by other tools.
sub as_xml {
my($self) = @_;
my $serialize = __PACKAGE__::XML->new;
$serialize->XMLout(
$self->{_xml},
GroupTags => {
Images => "Image",
},
KeyAttr => {
ParameterGroup => "+ID",
Parameter => "+key",
Image => "+key",
},
RootName => "TestResult",
XMLDecl => '<?xml version="1.0" encoding="UTF-8" ?>',
);
}
Return a true value to indicate that the module loaded successfully.
1;
Upvotes: 2
Reputation: 98378
XML::Simple expects you to assemble your output into a perl datastructure and then it converts it to XML; are you having trouble with the actual call to produce the XML, with figuring out what the datastructure should look like, or with populating it with your data? (Or something completely different?)
Break your problem down and solve it one bit at a time.
Upvotes: 1