HTML-Template - Array of Hash - perl

I have two Array of Hashes: The first contains values for a current time interval and the second contains values for a previous time interval.
#AoHcurrent=
( { node => "ABC",
link => "DEF",
time => "10:00",
value => "100",
},
{
node => "FGH",
link => "IJK",
time => "10:00",
value => "200",
},
);
#AoHprevious=
( { node => "ABC",
link => "DEF",
time => "09:45",
value => "10",
},
{ node => "FGH",
link => "IJK",
time => "09:45",
value => "50",
},
);
I want to now use HTML-Template to present this data. Something like :
NODE LINK VALUE
---------------------
ABC DEF 100(10)
FGH IJK 200 (50)
the values in brackets represent the previous value.
my %html_template_parameters =
( AOHCURRENT => \#AoHcurrent,
AOHPREVIOUS => \#AoHprevious, );
my $html_template=qq{Report.tmpl};
my $html_output=qq{Report.html};
htmlReport($html_template,$html_output,\%html_template_parameters);
where htmlReport is a function that generates the report
I require guidance on defining the Report.tmpl file.
Thanks you in advance

see also http://www.perlmonks.org/?node_id=972954
I gave an example there how this can be solved with HTML::Template::Compiled.
Basically you would navigate through the parameter stash like this:
[%= expr=".AOHPREVIOUS[__index__]{'value'}" %]
or with the classic syntax:
<TMPL_VAR expr=".AOHPREVIOUS[__index__]{'value'}" >

You can't do that with 2 separate lists just with HTML::Template. And trying to do it with HTML::Template::Expr would be a nightmare to maintain. Try collapsing them into a single list where the hash data is merged.

Related

Example for creating split-transaction in Perl Finance::QIF

I need to import my bank-exported transactions (CSV) into GNUcash.
I am almost finished with the perl script using Finance::QIF
I parse the CSV and write it out like this:
my $record = {
header => "Type:Bank",
date => $outdatum,
memo => $outtext,
transaction => $outbetrag,
};
$out->header( $record->{header} );
$out->write($record);
....
But my problem is creating a split.
http://finance-qif.sourceforge.net/ says " If the transaction contains splits this will be defined and consist of an array of hash references. With each split potentially having the following values." - so I tried this:
my $record = {
header => "Type:Bank",
date => $outdatum,
memo => $outtext,
transaction => $outbetrag,
#splits = (
{
category => "Gesundheit:Arzt:Kind1",
memo => "L",
amount => "-161,66"
},
{
category => "Gesundheit:Arzt:Kind2",
memo => "F",
amount => "-162,66"
}
)
};
This leads to the error:
Unsupported field 'HASH(0x221c9e8)' found in record ignored in file '>_TESTqif.qif' line 22 at convert_bank_CSV.pl line 195.
Unfortunately, I nowhere found an example for creating a split, just for a normal transaction.
Can someone please help how Finance::QIF can be used to create split-transactions?
I know nothing about Finance::QIF but your #splits code makes no sense.
Try this instead:
my $record = {
header => "Type:Bank",
date => $outdatum,
memo => $outtext,
transaction => $outbetrag,
splits => [
{
category => "Gesundheit:Arzt:Kind1",
memo => "L",
amount => "-161,66",
},
{
category => "Gesundheit:Arzt:Kind2",
memo => "F",
amount => "-162,66",
}
],
};
See perldoc perlreftut for more information about references and data structures in Perl.

How to keep orders in MongoDB?

In my MongoDB document I have object like this
[_id] => MongoId Object (
[$id] => 52a46b44aabacb5c218b4567
)
[results] => Array (
[http://google.com] => Array (
[position] => 1
[data] => 42672
)
[http://bing.com] => Array (
[position] => 2
[data] => 9423
)
[http://yandex.com] => Array (
[position] => 3
[data] => 5513
)
)
I would like to change data parameter in "bing.com" from 9423 to for instance 300. Moreover, I have to keep order of the sites. It have to looks like this
[_id] => MongoId Object (
[$id] => 52a46b44aabacb5c218b4567
)
[results] => Array (
[http://google.com] => Array (
[position] => 1
[data] => 42672
)
[http://bing.com] => Array (
[position] => 2
[data] => 300
)
[http://yandex.com] => Array (
[position] => 3
[data] => 5513
)
)
Is this achievable in Mongo?
The reordering of fields issue has been fixed as of MongoDB v2.5.2 (2.6 release). Having said that one way you can avoid the issue completely is having results as an array instead of a (sub)document. Also note you should not use "." as part of the key name either.
With 2.4, with the following you will see there is reodering in the case of _id=1 (subdocument) but not in the case of _id=2 (array).
$document = array("_id" => 1, "results" => array('http://google.com' => array('position' => 1, 'data' => 42672),
'http://bing.com' => array('position' => 2, 'data' => 9423),
'http://yandex.com' => array('position' => 3, 'data' => 5513)));
$coll->insert($document);
$document = array("_id" => 2, "results" => array(array('site' => 'http://google.com', 'data' => 42672),
array('site' => 'http://bing.com', 'data' => 9423),
array('site' => 'http://yandex.com', 'data' => 5513)));
$coll->insert($document);
$coll->update(array("_id" => 1), array('$set'=>array("results.http://bing.com.data"=>300)));
$coll->update(array("_id" => 2, 'results.site' => 'http://bing.com'), array('$set'=>array('results.$.data'=>300)));
I've included examples below using the mongo shell for clarity, but the PHP equivalent should be straightforward to work out.
I notice you originally modelled your list of sites as an embedded document, however the order of fields within an embedded document is currently not guaranteed to be preserved so you should instead use an array.
Additionally, you cannot use field names with embedded dots (.) in MongoDB so you should not plan to store urls as field names (see: Field name restrictions).
In order to find an element in an array you need to search by a value (not a field name) so your schema should look more like:
{
_id: ObjectId("52a46b44aabacb5c218b4567"),
results: [
{
site: 'http://google.com',
position: 1,
data: 42762
},
{
site: 'http://bing.com',
position: 2,
data: 9423
},
{
site: 'http://yandex.com',
position: 3,
data: 5513
}
]
}
Assuming the array site elements are unique, you can use the positional operator $ to find and update the matching embedded document in place.
For example, to perform your update of the "bing.com" data value:
db.sites.update(
// Match criteria
{
_id:ObjectId("52a46b44aabacb5c218b4567"),
'results.site':'http://bing.com'
},
// Update
{ $set: {
'results.$.data': 300 }
}
)
In MongoDB 2.4+ you have the option of pushing to a sorted array which could also be a useful approach to maintaining your array in sorted order when you add new entries.
It's worth noting that if you plan to store many (i.e. thousands) of items in an array this can impose a significant performance penalty due to document growth and the complexity of updating large arrays.
I am pretty sure that (as every other DBMS) you can't and should't rely on records orders.
Instead I would advice you to add index (on position, i.e. db.people.ensureIndex( { position: 1 } )) and query your record sorted by that field, i. e.: db.collection.find().sort( { position: 1 } )

Build and Access a Complex Data Structure Using Perl

I have a large one-dimensional hash with lots of data that I need to structure in such a way that I can sort it easily into a format that is the same each time the code executes.
Original Hash Data:
{
'datetime' => 'datetime value',
'param_name' => 'param name',
'param_value' => 'param value',
'category' => 'category name'
}
Current Data Structure:
{
'datetime value' => {
'category' => {
'param_name' = > 'param name',
'param_value' => 'param value
}
}
}
I can almost build this structure in code, except for every category, there could be multiple param_names and param_values with the same key name.
The problem I have is that if there are multiple param names/values, only the last pair are saved in the new data structure.
I know that keys have to be unique, so I'm not quite sure how to resolve this as of yet.
Once the structure is built, I then need to understand how to sort the data based on datetime, then param_name so that the order is always the same in the output.
Looking at the difference between your first and second example, I think you have your structure a bit off. I think this matches more of what you want:
{
DATE => date_time_value,
PARAMETERS => {
param_name1 => parameter_value1,
param_name2 => parameter_value2
}
}
This way, the structure with data may look like this:
{
DATE_TIME => "10/31/2031 12:00am",
PARAMETERS => {
COLOR => "red",
SIZE => "Really big",
NAME => "Herman",
}
}
Usually, you think of objects having fields which contain values. Think of a row of a SQL table or a spreadsheet. You have columns with headings, and rows that contain the value.
Let's take an employee. They have a name, age, job, and a phone number:
{
NAME => "Bob Smith",
AGE => "None of your business",
JOB => "Making your life miserable",
PHONE => "555-1212"
}
Unlike a table, each entry could contain other structure. For example, people usually have more than one phone number, and we might want to store the last name separate from the first name:
{
NAME => {
FIRST => "Bob",
LAST => "Smith"
}
AGE => "None of your business",
JOB => "Making your life miserable"
PHONE => {
CELL => "555.1234",
WORK => "555.1212"
}
}
Then we have the people who have multiple phones of the same time. For example, Bob has two cell phones. In this case, we'll make each phone type field an array of values:
{
NAME => {
FIRST => "Bob",
LAST => "Smith",
}
AGE => "None of your business",
JOB => "Making your life miserable"
PHONE => {
CELL => ["555.1234", "555.4321"]
WORK => ["555.1212"]
}
}
And to initialize it:
my $person = {};
$person->{NAME}->{FIRST} = "Bob";
$person->{NAME}->{LAST} = "Smith";
$person->{AGE} = "None of your business";
$person->{JOB} = "Making your life miserable";
$person->{PHONE}->{CELL}->[0] = "555.1234";
$person->{PHONE}->{CELL}->[1] = "555.4321";
$person->{PHONE}->{WORK}->[0] = ""555.1212";
I think it seems appropriate to have a params hash where the keys are all of the names and the values are the actual values. It seems like that is what you want.
my %hash = {
'datetime value' => {
'category' => {
'params' => {
'param-name1' => 'param-value1',
'param-name2' => 'param-value2',
'param-name3' => 'param-value3',
etc..
}
}
}
}
After this restructuring it should be pretty easy to sort based on whatever you would like.
alphabetically by key:
my #alphabetic_keys = sort { $hash{$a} cmp $hash{$b} } keys %{ $hash{params} };
length by key:
my #by_length_keys = sort { length($a) <=> length($b) } keys %{ $hash{params} };
Assuming category names are unique, I would suggest the following data structure:
{
'datetime value 1' => {
'category name 1' => {
'param name 1' = > [param value1, param value2, ...],
'param name 2' = > [param value3, param value4, ...],
etc...
},
'category name 2' => {
'param...' => [ value... ]
},
'datetime value 2' => {
etc...
}
}

Perl hash of hashes

I have a file with a list of lines like
at 12345 injected value 1 to 'signal_A'
at 12345 injected value 0 to 'signal_B'
at 12346 injected value 1 to 'signal_A'
at 12348 injected value 1 to 'signal_A'
at 12350 injected value 0 to 'signal_A'
at 12354 injected value 0 to 'signal_A'
From this file, I want to read till the end of the file and I want to build a hash of hashes something like
%tab = (
12345 => {
signal => "signal_A",
value => "1",
},
12345 => {
signal => "signal_B",
value => "1",
},
);
Also I want to iterate this hash table.
Will highly appreciate your help.
You have two elements with the same key. That data structure cannot exist. How about the following instead:
%tab = (
12345 => [
{
signal => "signal_A",
value => "1",
},
{
signal => "signal_B",
value => "1",
},
],
12346 => [
{
signal => "signal_A",
value => "1",
},
],
...
);
You'd use the following to created it
push #{ $tab{$id} }, { signal => $signal, value => $value };
You can iterate over the structure using
for my $id (keys %tab) {
for $event (#{ $tab{$id} }) {
...$event->{signal}...;
...$event->{value}...;
}
}

Why am I getting a "Odd number of elements in anonymous hash" warning in Perl?

Help, I'm trying to create a new post in my wordpress blog with custom fields using the following perl script using metaweblogAPI over XMLRPC, but there seems to be an issue with the custom fields. Only the second custom field (width) ever seems to get posted. Can't get the "height" to publish properly. When I add another field, I get the "Odd number of elements in anonymous hash" error. This has got to be something simple - would someone kindly sanity check my syntax? Thanks.
#!/usr/bin/perl -w
use strict;
use RPC::XML::Client;
use Data::Dumper;
my $cli=RPC::XML::Client->new('http://www.sitename.com/wp/xmlrpc.php');
my $appkey="perl"; # doesn't matter
my $blogid=1; # doesn't matter (except blogfarm)
my $username="Jim";
my $passwd='_____';
my $text=<<'END';
This is the post content...
You can also include html tags...
See you!
END
my $publish=0; # set to 1 to publish, 0 to put post in drafts
my $resp=$cli->send_request('metaWeblog.newPost',
$blogid,
$username,
$passwd,
{
'title' => "this is doodoo",
'description' => $text,
'custom_fields' => {
{ "key" => "height", "value" => 500 },
{ "key" => "width", "value" => 750 }
},
},
$publish);
exit 0;
While techically valid syntax, it's not doing what you think.
'custom_fields' => {
{ "key" => "height", "value" => 500 },
{ "key" => "width", "value" => 750 }
},
is roughly equivalent to something like:
'custom_fields' => {
'HASH(0x881a168)' => { "key" => "width", "value" => 750 }
},
which is certainly not what you want. (The 0x881a168 part will vary; it's actually the address where the hashref is stored.)
I'm not sure what the correct syntax for custom fields is. You can try
'custom_fields' => [
{ "key" => "height", "value" => 500 },
{ "key" => "width", "value" => 750 }
],
which will set custom_fields to an array of hashes. But that may not be right. It depends on what send_request expects.