1

I have a script that curls a webpage and pulls out a table. I have gotten it to the point where

echo "<table>";
echo $table;
echo "</table>;

will output the table I am looking for, but what I need is for it to be in an array, so I can look at every row individually. The first row of the table has the column names, if that makes things any easier. Below is the format of the table:

<pre>
  <table>
    <tbody id="sortable1">
      <tr id="skip_coloring" class="nosort">
      <tr>
        <td class="border_even" style="white-space:nowrap">06/20/2011 4:33 PM </td>
        <td class="border_even">
          <strong>user_name, ext</strong>
        </td>
        <td class="border_even"> outside_num </td>
        <td class="border_even"> outgoing </td>
        <td class="border_even"> 12m, 14s </td>
        <td class="border_even"> 12m, 5s </td>
      <tr>
      <tr>
    </tbody>
  </table>
</pre>

id=skip_coloring has the column names. All other rows are data. Im using preg_match to get the table; if there is a better way to do it, let me know. Right now, I am using the following preg_match to get this table:

preg_match('#<table[^>]*id="row1"[^>]*>(.+?)<\\/table>#is', $cres_data, $matches);

but $matches is an array with 2 indexes, one for each page of results that the table creates. Maybe it would be better to try and match against each row within the table? I seem to recall that this could be done with simplexml or something, but I haven't gotten there yet. Any help is appreciated.

edit

Ended up using DOM; here's what I've got now:

$dom = new DomDocument();
$dom->loadHTML($cres_data);
$xpath = new DOMXPath($dom);

//get the first row of values
$arr = array();
foreach ($xpath->query('//tbody[@id="sortable1"]/tr/td') as $node)
        {
        $arr[] = $node->nodeValue;
        }
echo '<pre>';
print_($arr);

The output, however, isn't quite right:

Array
    (
    [0] => 

          Call Date 
    [1] => 

          Call From

.
.
.
    [7] => 







     06/20/2011  4:33 PM






    [8] => 







     user_name <ext>

Is there some way to remove all the whitespace, and get the column names as index labels? I assume I'd need to do this twice, or embed an additional foreach...it will always be formatted the same, if that matters.

edit

Used this function on both the labels and data to properly format it:

$label_arr =  array_filter(array_map('trim',$label_arr));

Output was exactly what I need.

Array
(
    [Call Date] =>  06/20/2011  4:33 PM
    [Call From] =>  user_name <ext>
    [Call To] =>  outside_num
    [Call Type] =>  outgoing
    [Call Time] =>  12m, 14s
    [Talk Time] =>  12m, 5s
)
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
tsz
  • 307
  • 4
  • 18
  • As everyone will tell you don't try to parse HTML using regex. HTML is not a regular language. Trying to use regex to parse might work at first glance but will most definitively bite you in the ass later :) – PeeHaa Jun 29 '11 at 16:23

5 Answers5

2

You're better off with DomDocument's loadHTML and DomXPath. I believe this will do the trick, but it is untested:

$dom = new DomDocument();
$dom->loadHTML( $your_table );
$xpath = new DOMXPath( $dom );

$arr = array();
foreach ($xpath->query('//td') as $node) {
    $arr[] = $node->nodeValue;
}
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
  • in the loadHTML bit, how do I include the table, when I havent segrated it from the page I took it from yet? I'm going though the dom manual now.. – tsz Jun 29 '11 at 16:36
  • I believe all you'd have to do is change the xpath to: `'//tbody[id="sortable1"]td'`, but I don't recall at the moment. – cwallenpoole Jun 29 '11 at 16:38
  • I cant seem to get it to do much but place the entire array into a single index; I've tried creating an additional foreach() below the original query to get the rows, but it doesn't like that $node is already an object. Would a query similar to '//div[@id="main1"]/tr' show me rows? – tsz Jun 29 '11 at 17:55
  • ohh, just found an excellent description of the query function. I will report back with better findings. – tsz Jun 29 '11 at 17:58
1

What you should do is parse this HTML with a DOM parser instead of regex. It will save you a lot of headache.

See How do you parse and process HTML/XML in PHP?

Community
  • 1
  • 1
Brad
  • 159,648
  • 54
  • 349
  • 530
0

You need to use some DomDocument functions.

Don't use a regex.

Naftali
  • 144,921
  • 39
  • 244
  • 303
0

I would use Dom Document to parse the html rather than regexp.

Jacob Eggers
  • 9,062
  • 2
  • 25
  • 43
0

Apart From DOM Document as everyone suggested, you can use custom functions like "explode" to parse the pages, if the structure of the pages will remain the same.

SO, lets say $html = "HTML COntent";

$tables = explode("<table>", $html);

$table = $tables[1]; //Part after <table>

$table = explode("</table>", $table);
$table = $table[0]; //Part before </table>, so $table contains your table.

and then

$rows = explode("<tr>", $table);

// $rows[0] = to be neglected, it contains the part before the first <tr>
// $rows[1] = First TR, so your Heading row
//$rows[1-n] = Your data rows.

so

for ($i=2; $i<count($rows);$i++){
//process each row Here
}
Pheonix
  • 6,049
  • 6
  • 30
  • 48