creating table from 2-Dimensional array in perl has different outputs - html

Hi I am generating table from a 2-Dimensional array in perl.
But the output of my program is different if viewed in browser and viewing page source using developers tool in chrome:
Let me explain-
I have a subroutine to print the table from #RESULT array, the code is below
sub printTableFormattedEmpty {
my #array= #_ ;
print "<table border='0' cellspacing='0' bgcolor='#cfcfcf' cellpadding='0'>\n";
for(my $row_i = 0; $row_i < #array; $row_i++) {
print "<tr style='background-color:#B39DB3;'>\n";
for(my $column_i = 0; $column_i < #{ $array[$row_i] }; $column_i++) {
my $th = ($row_i == 0) ? "th" : "td";
print "</$th>";
print "$array[$row_i][$column_i]";
my $close = ($row_i == 0) ? 'th' : 'td';
print "</$close> \n";
}
print "</tr> \n";
}
print "</table> \n";
}
and i am calling the subroutine as
{
print "Table starts here!\n";
#$RESULT[0]- is array of many elements. u can see in output image
$RESULT[1][0]= 'No Active bookings available for you !';
$RESULT[2][0]= 'Click here to create new Booking !';
&printTableFormattedEmpty(#RESULT);
}
Now here i am not getting the expected output in a table , i am getting different output as shown in 2 figure:
when i inspect element and inspect the table i get:
But when i view page source of the page iam getting output formatted as table as shown in the fig:
I am really confused with this two types of Output, the both images are of the same page without refreshing.
How is this possible!
Did i do any mistake in my program or its something else.
Please Help me with This.

This is a typo!
There is a slash / in your opening HTML tag output.
for(my $column_i = 0; $column_i < #{ $array[$row_i] }; $column_i++) {
my $th = ($row_i == 0) ? "th" : "td";
# V HERE
print "</$th>";
print "$array[$row_i][$column_i]";
my $close = ($row_i == 0) ? 'th' : 'td';
print "</$close> \n";
}
Remove that slash and it will be fine.
As to why your two outputs are different: The HTML inspector shows the DOM structure after it has been parsed by the browser. It does not include invalid elements. Since stray closing elements are not valid, it's likely the parser just omitted them, so they are gone.
Viewing the source code on the other hand shows the real, unparsed code, which contains the wrong markup with the faulty HTML tags included. That is also where I saw the extra slashes. (read: your variable names are badly chosen. You would have seen it yourself had it been something like $open_tag and $closing_tag).

Related

How to keep metadata fields on one line

I am trying to customize the metadata for my posts. Specifically, I want to change the separator from the default forward slash (/) to a vertical line (|). I also want to add the word "Updated" before the date displayed. And, I want to keep the option to display reading time. (*FYI: I know basically nothing about coding, just trying to override the metadata output from Astra)
I used this code to change the separator (found in a post about how to customize post meta in Astra theme):
add_filter('astra_single_post_meta', 'custom_post_meta');
function custom_post_meta($old_meta)
{
$post_meta = astra_get_option('blog-single-meta');
if (!$post_meta) return $old_meta;
$new_output = astra_get_post_meta($post_meta, "|");
if (!$new_output) return $old_meta;
return "<div class='entry-meta'>$new_output</div>";
}
See the output in image 1 - looks great!
output of new code for separator
This is close, but still needed to add "Updated" before the date. So, I used this code (from same post mentioned above):
function astra_post_date()
{
$format = apply_filters('astra_post_date_format', '');
$published = esc_html(get_the_date($format));
$modified = esc_html(get_the_modified_date($format));
$output = '<p class="posted-on">';
$output .= 'Updated: <span class="published" ';
$output .= 'itemprop="datePublished">' . $published;
$output .= '</span>';
$output .= '</p>';
return apply_filters('astra_post_date', $output);
}
See output in image 2 - content is perfect, but formatting is wrong. Can't figure out how to edit the code to get all 3 fields on the same line.
output of new code for adding "Update"
What do I need to change in the 2nd block of code to keep everything on one line like the 1st block of code?
Thanks for any help!

Compare a current user against a list of employees logged into computers Perl, CGI

Not sure I am doing this correctly as it doesn't appear to be working.
Is this the correct way to declare my users, and is the If statement correctly formated?
At the top I have declared:
my $las = 'jpietrza hpietrza oszones';
These are employees we are checking against current users.
Further down in the code, I want to change the text color that is printed if the user is in the list vs. someone else.
while ( $sth->fetch() ) {
next unless defined $currentuser;
$lastlogin =~ s/ .*$//;
$host_name =~ s/1408//;
foreach ( #las ) {
if ( $currentuser eq "$_" ) {
$lacolor = "black";
last;
}
else {
$lacolor = "red";
}
}
print "<tr>";
print "<td>$host_name</td>";
print "<td><font color=\"$lacolor\">System In-Use (User Undisclosed)</font></td><td> </td>";
}
maybe there was nothing wrong with the if statement, but the whole 9 lines of code can be condensed to 1 very readable line:
$lacolor = any { /^$currentuser$/ } #las ? "black" : "red";
please
use List::Util qw/any/;
while($sth->fetch()) {
# $currentuser is assigned between the 'while' and this 'next' statement ?
# if not, then outside the loop and do not loop at all unless defined
next unless defined $currentuser;
$lastlogin=~s/ .*$//;
$host_name=~s/1408//;
$lacolor = any { /^$currentuser$/ } #las ? "black" : "red";
print "<tr>";
print "<td>$host_name</td>";
print "<td><font color=\"$lacolor\">System In-Use (User Undisclosed)</font></td><td> </td>";
}
please, also use strict; and use warnings;
I figured out how to put the array together correctly:
my #las = qw(
jpietrza
hpietrza
oszones
);
instead of:
my $las='
jpietrza
hpietrza
oszones
';
Firstly, as I think you have worked out now, the scalar variable $las and the array #las are completely different. As you've seen, you should declare and initialise your array like this:
my #las = qw(
jpietrza
hpietrza
oszones
);
Actually, I suspect this all gets easier if you store this in a hash, not an array;
my %las = map { $_ => 1 } qw(jpietrza hpietrza oszones);
Then your check just becomes:
my $lacolour = $las{$currentuser} ? 'black' : 'red';
A few more points:
Please add use strict and use warnings. And understand and fix the problems they reveal.
The quotes are unnecessary in if ($currentuser eq "$_").
Using a templating system to create the output will make your life a lot easier.
Update: Oh, and one I forgot earlier. It's 2017. No-one has used the font element in HTML for fifteen years. Take a look at CSS.

as_html in HTML::TagParser

I'm working in perl
I would like to ask if there is something like
$value->as_html()
from HTML::TreeBuilder in HTML::TagParser;
I extracted tag which I needed in HTML::TagParser, but now the only option is:
$value->innerText();
which give me only text without HTML tags
Or maybe can I somehow connect result from HTML::TagParser with HTML::TreeBuilder, and take my HTML tags like this?
The HTML::TagParser does not only read the element content. It also keeps the element name and the attribute key/value pairs for each selected element. Therefore you can easily reproduce the complete HTML code of the element.
Actually, the HTML::TagParser CPAN page contains an example for this: The following code extracts all <a>nchor tags from a web page and reproduces them into an HTML fragment listing precisely these tags.
my $url = 'http://www.kawa.net/xp/index-e.html';
my $html = HTML::TagParser->new( $url );
my #list = $html->getElementsByTagName( "a" );
foreach my $elem ( #list ) {
my $tagname = $elem->tagName;
my $attr = $elem->attributes;
my $text = $elem->innerText;
print "<$tagname";
foreach my $key ( sort keys %$attr ) {
print " $key=\"$attr->{$key}\"";
}
if ( $text eq "" ) {
print " />\n";
} else {
print ">$text</$tagname>\n";
}
}
This works pretty well for simple element scanning. For more complex tasks (e.g. mixed inner HTML content) I would prefer to work with HTML::Parser.

Perl parse links from HTML Table

I'm trying to get links from table in HTML. By using HTML::TableExtract, I'm able to parse table and get text (i.e. Ability, Abnormal in below example) but cannot get link that involves in the table. For example,
<table id="AlphabetTable">
<tr>
<td>
Ability <span class="count">2650</span>
</td>
<td>
Abnormal <span class="count">26</span>
</td>
</table>
Is there a way to get link using HTML::TableExtract ? or other module that could possibly use in this situation. Thanks
part of my code:
$mech->get($link->url());
$te->parse($mech->content);
foreach $ts ($te->tables){
foreach $row ($ts->rows){
print #$row[0]; #it only prints text part
#but I want its link
}
}
HTML::LinkExtor, passing the extracted table text to its parse method.
my $le = HTML::LinkExtor->new();
foreach $ts ($te->tables){
foreach $row ($ts->rows){
$le->parse($row->[0]);
for my $link_tag ( $le->links ) {
my ($tag, %links) = #$link_tag;
# next if $tag ne 'a'; # exclude other kinds of links?
print for values %links;
}
}
}
Use keep_html option in the constructor.
keep_html
Return the raw HTML contained in the cell, rather than just the visible text. Embedded tables are not retained in the HTML extracted from a cell. Patterns for header matches must take into account HTML in the string if this option is enabled. This option has no effect if extracting into an element tree structure.
$te = HTML::TableExtract->new( keep_html => 1, headers => [qw(field1 ... fieldN)]);

Ignoring unclosed tags from another <div>?

I have a website where members can input text using a limited subset of HTML. When a page is displayed that contains a user's text, if they have any unclosed tags, the formatting "bleeds" across into the next area. For example, if the user entered:
Hi, my name is <b>John
Then, the rest of the page will be bold.
Ideally, there'd be someting I could do that would be this simple:
<div contained>Hi, my name is <b>John</div>
And no tags could bleed out of that div. Assuming there isn't anything this simple, how would I accomplish a similar effect? Or, is there something this easy?
Importantly, I do not want to validate the user's input and return an error if they have unclosed tags, since I want to provide the "easiest" user interface possible for my users.
Thanks!
i have solution for php
<?php
// close opened html tags
function closetags ( $html )
{
#put all opened tags into an array
preg_match_all ( "#<([a-z]+)( .*)?(?!/)>#iU", $html, $result );
$openedtags = $result[1];
#put all closed tags into an array
preg_match_all ( "#</([a-z]+)>#iU", $html, $result );
$closedtags = $result[1];
$len_opened = count ( $openedtags );
# all tags are closed
if( count ( $closedtags ) == $len_opened )
{
return $html;
}
$openedtags = array_reverse ( $openedtags );
# close tags
for( $i = 0; $i < $len_opened; $i++ )
{
if ( !in_array ( $openedtags[$i], $closedtags ) )
{
$html .= "</" . $openedtags[$i] . ">";
}
else
{
unset ( $closedtags[array_search ( $openedtags[$i], $closedtags)] );
}
}
return $html;
}
// close opened html tags
?>
you can use this function like
<?php echo closetags("your content <p>test test"); ?>
You can put the HTML snippet through Tidy, which will do its best to fix it. Many languages include it in some fashion or another, here for example PHP.
This can't be done.
Don't let users invalidate your HTML.
If you don't want to let users fix their errors, then try to clean it up automatically for them.
You can parse the data entered by the user. Thats what an XML does. You may need to parse or replace the standard html or xml symbols like '<', '>', '/', '&', etc... with '&lt', '&gt', etc...
In this way you can achieve whatever you want.
There is a way to do this using HTML and javascript. I wouldn't recommend this method for public-facing websites; you should clean your data before it reaches the browser. But it might be useful in other situations.
The idea is to put the potentially invalid content into a noscript tag, like this:
<noscript class="contained">
<div>Hi, my name is <b>John</div>
</noscript>
... and then add javascript that will load it into the DOM. Using jQuery (but probably not necessary):
$("noscript.contained").each(function () {
$(this).replaceWith(this.innerText);
});
Note that users without javascript will still experience the "bleeding" that you are trying to avoid.