XML::Simple removes root element - perl

Hi I have a xml data which i get from array of hashes and when I do a Dumper on it the output is as follows:
$var1=
'<Data>
<Data1>ABC</Data1>
<Data2>ABCD</Data2>
</Data>';
This I have in a variable call $var1. Now I am using XML::Simple on it.. it is somewhat like: {Data1=>'ABC',Data2=>'ABCd'};
The first tag Data is gone. What is wrong?

Seems to be well-documented:
KeepRoot => 1:
In its attempt to return a data structure free of superfluous detail
and unnecessary levels of indirection, XMLin() normally discards the
root element name. Setting the KeepRoot option to 1 will cause the
root element name to be retained. So after executing this code:
$config = XMLin('<config tempdir="/tmp" />', KeepRoot => 1)
You'll be able to reference the tempdir as
"$config->{config}->{tempdir}" instead of the default
"$config->{tempdir}".

Related

Perl Concatenating 2 hashes based on a certain key

Hi I have two hashes %Asset & %Activity
%Asset
Name,Computer Name
David,X
Clark,Y
Sam,Z
%Activity
Name,Activity
David,A
Clark,B
Sam,C
David,D
Clark,E
Sam,F
The second hash has the name repeated multiple times (can be more than 2) .. I want to get a hash with the concise infromation.. something like
Name,Computer Name,Activity
David,X,A&D
Clark,Y,B&E
Sam,Z,C&F
my idea in a pseudo code kind of way is;
foreach (#Activity{qw[Name]}) {
push #Asset{qw[Name Activity]}, $Activity['Activity']
}
What you want is a hash of hashes. Conceptually, you'd combine all information about an asset into a single hash.
my %dave = (
name => "Dave",
computer_name => "X",
activity => "A"
);
Then this goes into a larger hash of all assets keyed by their name.
$Assets{$dave{name}} = \%dave;
If you want to find Dave's activity...
print $Assets{Dave}{activity};
You can pull out all information about Dave and pass it around as a hash reference.
my $dave = $Assets{Dave};
print $dave->{activity};
This sort of structure inevitably leads to modelling your assets as objects.
You can learn more about hashes of hashes in the Perl Data Structures Cookbook.

Removing a key from a Perl hash

I have a hash in which its keys are hashes. I want to rename some of the keys inside the primary hash by adding a key with the desired name and deleting the unwanted key. I succeeded in adding a key, but I'm unable to delete the original key.
This statement isn't working
delete $primary_hash{$sec_hash_key};
If I print the value of $primary_hash{$sec_hash_key} it's returning $HASH(0X*). I don't know what is missing in syntax?
In Perl, hash keys are always strings. If you specify a non-string object as a hash key, perl will stringify it to be able to use it as a key. Therefore, when you say:
I have hash in which it's [sic] keys are hashes
you are wrong. They are not hashes, they are strings.
Now, if you did something like:
my %h = (a => 1);
my %g = (%h => 2);
That would have created %g as:
(a => 1, 2 => undef);
If, instead, you did %g = (\%h => 2), that would have created something along the lines of:
%g = (
'HASH(0x7ff92882cbd8)' => 2
);
Note that the key is a string. You cannot go back to the data structure from that string.
What do you mean by 'delete'? Free the memory, or just want the
key to be undefined, when checking for it in an if statement?
The latter you can achieve my setting the key undef.
$primary_hash{$sec_hash_key} = undef;.
But please provide a full working example of your problem, so
it can be reproduced.

What does #data actually contain in PDF::Report::Table $table_write->addTable(#data);?

I think I've got the gist of creating a table using Perl's PDF::Report and PDF::Report::Table, but am having difficulty seeing what the 2-dimensional array #data would look like.
The documentation says it's a 2-dimensional array, but the example on CPAN just shows an array of arrays test1, test2, and so on, rather than the example showing data and formatting like $padding $bgcolor_odd, and so on.
Here's what I've done so far:
$main_rpt_path = "/home/ics/work/rpts/interim/mtr_prebill.rpt";
$main_rpt_pdf =
new PDF::Report('PageSize' => 'letter', 'PageOrientation' => 'Landscape',);
$main_rpt_tbl_wrt =
PDF::Report::Table->new($main_rpt_pdf);
Obviously, I can't pass a one dimensional array, but I have searched for examples and can only find the one in CPAN search.
Edit:
Here is how I am trying to call addTable:
$main_rpt_tbl_wrt->addTable(build_table_writer_array($pt_column_headers_ref, undef));
.
.
.
sub build_table_writer_array
# $data -- an array ref of data
# $format -- an array ref of formatting
#
# returns an array ref of a 2d array.
#
{
my ($data, $format) = #_;
my $out_data_table = undef;
my #format_array = (10, 10, 0xFFFFFF, 0xFFFFCC);
$out_data_table = [[#$data],];
return $out_data_table;
}
and here is the error I'm getting.
Use of uninitialized value in subtraction (-) at /usr/local/share/perl5/PDF/Report/Table.pm line 88.
at /usr/local/share/perl5/PDF/Report/Table.pm line 88
I cannot figure out what addTable wants for data. That is I am wondering where the formatting is supposed to go.
Edit:
It appears the addData call should look like
$main_rpt_tbl_wrt->addTable(build_table_writer_array($pt_column_headers_ref), 10,10,xFFFFFF, 0xFFFFCC);
not the way I've indicated.
This looks like a bug in the module. I tried running the example code in the SYNOPSIS, and I got the same error you get. The module has no real tests, so it is no surprise that there would be bugs. You can report it on CPAN.
The POD has bugs, too.
You increase your chances of getting it fixed if you look at the source code and fix it yourself with a patch.

join() function is returning the type followed by a hex number instead of a concatenated string

In essence, I want to take an array and create a single string with the elements of said array separated by a newline.
I have an array named $zones. Outputting the reference to $zones confirms it's an array.
The following code:
print_log(Dumper($zones));
print_log('-------');
print_log(Dumper(join("\n",$zones)));
results in the following output
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = [
'fake.com25',
'fake.com2',
'fake.com27',
'fake.com43',
'fake.com41',
'fake.com40',
'fake.com39',
'fake.com37',
'fake.com36',
'fake.com35',
'fake.com31',
'fake.com56',
'fake.com55',
'fake.com54',
'fake.com53',
'fake.com52',
'fake.com51',
'fake.com50',
'fake.com49',
'fake.com48',
'fake.com42',
'fake.com38',
'fake.com34',
'fake.com33',
'fake.com32',
'fake.com30',
'fake.com29',
'fake.com28',
'fake.com26',
'fake.com24',
'fake.com23',
'fake.com69',
'fake.com68',
'fake.com67',
'fake.com66',
'0',
'fake.com44',
'fake.com45',
'fake.com46',
'fake.com278'
];
[2013-06-15 16:23:29 -0500] info [dnsadmin] -------
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = 'ARRAY(0x170cf0d8)';
I really don't want to loop over this array manually. Can someone explain why the join() function is returning the name of the type along with a hex number?
How to do is explained well by user1937198, but why it works this way?
It's simple:
$zones is not an array. It's an array reference.
join works on lists. So if you do:
join("\n",$zones)
You essentially are calling join on a single-element list. And the element is a reference, which happens to stringify to ARRAY(0x170cf0d8).
To make it work correctly you have to dereference it, and it is done by prefixing with real datatype (# or %, or in some cases $).
This can be written like this: #$zones, or (some, including me, say that it's more readable) as: #{ $zones }.
This is important when you're having nested structures, because while you can have plain array as a variable, when you're dealing with nested data structures, it's always references.
what you want is join("\n",#{$zones}))
$zones is array reference and to join array values you have to dereference it first by prefixing scalar $zones with #
print_log(Dumper(join("\n",#$zones)));
For more info there is short tutorial on references:
http://perldoc.perl.org/perlreftut.html#NAME

Perl hash of hash of lists from Net::LDAP to a 'filtered' list

The Net::LDAP module for Perl provides an Net::LDAP::Search object. Its as_struct method returns the structure below.
Multiple entries as
$entry{dn=...} =
ref {cn} = ref {name}
ref {l} = ref {city}
ref{mail} = ref {xxxxxx}
An example:
uid=pieterb,ou=People,dc=example,dc=org {key of first hash = dn in ldap}
uid=pieterb {key=uid}
cn=Pieter B. {key=cn}
uidNumber=1000 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
uid=markc,ou=People,dc=example,dc=org {key of first hash = dn in ldap }
uid=markc {key=uid}
cn=Mark Cole {key=cn}
uidNumber=1001 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
However, the interface uses UI::Dialog which expects a list in the format below (radiolist/checklist), with data coming from the attribute values in the LDAP server
list => [
'Pieter B.', ['uid=pieterb,ou=People,dc=example,dc=org',0],
'Mark Cole', ['uid=markc,ou=People,dc=example,dc=org',0],
'cn_value(openldap)',['dn_value',0],
'givenname_value(activedirectory)',['dn_value',0]
]
It is very hard to guess what you want, but I think it is a list of the LDAP attribute names versus their values.
You should look at Data::Dumper to examine and present the data structures you are dealing with.
You don't mention what to do if the data you get from the search contains multiple Distinguished Names, or multiple values for an attribute, but this code simply takes the first DN and the first value in lists of attribute values to generate a list of lists.
I have little doubt that this isn't exactly what you need, and if you specify your requirement better we will be able to help further.
my $data = $msg->as_struct;
my $entry = (values %$data)[0];
my #attributes = map {
$_, [$entry->{$_}[0], 0]
} keys %$entry;
$dialog->checklist(list => \#attributes);