Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

File parsing with HTML::TokeParser::Simple

by THRAK (Monk)
on Feb 24, 2005 at 19:01 UTC ( [id://434195]=perlquestion: print w/replies, xml ) Need Help??

THRAK has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write a utility to parse some PHP (w/HTML) files using HTML::TokeParser::Simple (HTS). I need to keep track of any problems I find by line number so I've opted loop through the file and parse each line with HTS using the string constructor. (This is the only way to know where you are within the file.) One of the first things I tried to detect is when the file goes into PHP mode by looking for processing instructions (is_pi). When I do this, it only detects 2 of the 5 occcurances. But if I rewrite it to parse the file via HTS's file constructor it finds all 5! I then wrote a quick test using HTML::TokeParser which indicates that the 2 missing PI's are being detected as comments. How is it that HTS using a file constructor works properly but yet the HTS string constructor and TokeParser don't work? At least if it was consistent that would make sense, but it's not. Here's some code that illustrates this situation:
#!/usr/bin/perl -w use strict; use warnings; use Data::Dumper; use HTML::TokeParser::Simple; $|++; #--- Variables my $file = 'test2.php'; my $line_number; print "#--- TokeParser::Simple String\n"; $line_number = 0; open (FH, "<$file") or die "Unable to open $file $!\n"; while (<FH>) { chomp; $line_number++; my $p = HTML::TokeParser::Simple->new(string => $_); while (my $token = $p->get_token) { if ($token->is_pi) { print $line_number . 'P: ' . $token->get_token0 . "\n"; } if ($token->is_comment) { print $line_number . 'C: ' . $token->as_is . "\n"; } } } close (FH); ############################## print "\n#--- TokeParser::Filehandle\n"; my $fh; open ($fh, "<$file") or die "Unable to open $file $!\n"; $line_number++; my $p = HTML::TokeParser::Simple->new(handle => $fh); while (my $token = $p->get_token) { if ($token->is_pi) { print $line_number . 'P: ' . $token->get_token0() . "\n"; } if ($token->is_comment) { print $line_number . 'Pc: ' . $token->as_is . "\n"; } } close ($fh); ############################## print "\n#--- TokeParser\n"; $line_number = 0; open (FH, "<$file") or die "Unable to open $file $!\n"; while (<FH>) { chomp; $line_number++; print "LINE: $line_number ********\n"; my $p = HTML::TokeParser->new(\$_); while (my $token = $p->get_token) { print Dumper($token) . "\n"; } } close (FH); __END__

Here is the code I'm running it against (test2.php):
<? /**** $Id$ ****/ ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ +/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <HTML> <BODY> <P>Some text<BR /> </P> <p><? echo U($date);?></p> <? echo 'This is from PHP.'; ?> <h1><? echo $h1; ?></h1> <?php ?> </body> </html>
And the output I get:
#--- TokeParser::Simple String 1C: <? /**** $Id$ ****/ 9P: echo U($date);? 10C: <? 13P: echo $h1; ? 14C: <?php #--- TokeParser::Filehandle 18P: /**** $Id$ ****/ ? 18P: echo U($date);? 18P: echo 'This is from PHP.'; ? 18P: echo $h1; ? 18P: php ? #--- TokeParser LINE: 1 ******** $VAR1 = [ 'C', '<? /**** $Id$ ****/' ]; --- SNIP! --- LINE: 10 ******** $VAR1 = [ 'C', '<?' ]; --- SNIP! --- LINE: 14 ******** $VAR1 = [ 'C', '<?php' ]; --- SNIP! --- This shows HTML::TokeParser sees those three lines as comments not as +PI's.

2005-02-24 Janitored by Arunbear - added readmore tags, as per Monastery guidelines

Replies are listed 'Best First'.
Re: File parsing with HTML::TokeParser::Simple
by Ovid (Cardinal) on Feb 24, 2005 at 20:08 UTC

    The problem is that you're trying to use the tool in a way it can't be used. Consider the following process instruction:

    <? echo 'This is from PHP.'; ?>

    That runs over three lines. However, if you're reading things in line-by-line, you lose all context. When HTS gets to an individual line, it can't parse it as a process instruction because it doesn't know that it is one. I'm afraid you'll have to take a different approach to solving your problem.

    I'm not sure there is a way around this problem, frankly, because the tokens will never have a direct correlation with line numbers. One possibility would be to (forgive me!) track the number of line endings in all tokens as a rough heuristic of which line a token is on.

    Cheers,
    Ovid

    New address of my CGI Course.

      Ah. Now that makes sense. I need to know the line numbers because I'm using this information to build a report of what is wrong in the file. Will need to rethink this (yet again). I guess I'll start with trying to process using HTS file constructor and count newlines as I go.

      You really should make HST keep track of what line it is on...because that's what I need!  ;)

      Other suggestions on how to build this wheel would be more than welcome. Thanks Ovid.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://434195]
Approved by kvale
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2024-04-23 09:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found