Parsing table and removing excess data - php

Im using the simpel dom parser to retrieve som data. But when i changed the table layout the parser stopped working. Im getting error PHP Fatal error: Call to a member function find() on null.
require('simple_html_dom.php');
$html = file_get_html($url);
$table = $html->find('table');
$rowData = array();
foreach($table->find('tr') as $row) {
// initialize array to store the cell data from each row
$stocks = array();
foreach($row->find('td') as $cell) {
// push the cell's text to the array
$stocks[] = $cell->plaintext;
}
$rowData[] = $stocks;
}
echo '<table>';
foreach ($rowData as $row => $tr) {
echo '<tr>';
foreach ($tr as $td)
echo '<td>' . $td .'</td>';
echo '</tr>';
}
echo '</table>';
Have a look at this pastebin (sorry for big table layout). It is from this table i want to extract the following th
+--------+--------+------+----+------+-------+--------+--------+---------+
| Aktie | Senast | +/- | % | Köp | Sälj | Högst | Lägst | Omsatt |
+--------+--------+------+----+------+-------+--------+--------+---------+
This snipp works, but it doesn't arrange the data in a table:
require('simple_html_dom.php');
$html = file_get_html($url);
// remove all image
foreach($html->find('img') as $e)
$e->outertext = '';
// Remove a attribute, set it's value as null!
foreach($html->find('a') as $e)
$e->href = null;
// Find all <td> in <table> which class=hello
foreach($html->find('table tr') as $es)
echo $es->innertext . '<br>';
My question:
How can i fetch the above mentioned th? and insert the corresponding data from td column?
Expected result is:
+-------------+--------+-------+-------+-------+-------+--------+--------+---------+
| Aktie | Senast | +/- | % | Köp | Sälj | Högst | Lägst | Omsatt |
+-------------+--------+-------+-------+-------+-------+--------+--------+---------+
| AAK AB | 549,90 | ..etc | ..etc | ..etc | ..etc | ..etc | ..etc | ..etc |
| ABB LTD | 149.80 | ..etc | ..etc | ..etc | ..etc | ..etc | ..etc | ..etc |
| and so on.. | | | | | | | | |
+-------------+--------+-------+-------+-------+-------+--------+--------+---------+

Do you have more than one table? If so, explicitly identify the table id
Get header: $e = $table->find('thead'); and do something to it get the table data, as you already did, and I would imagine that the indexes could implicitly create the relation between header and data.

Related

PHP: Troubles on indexing a nested for-loop

I am trying to print a 3-dimensional array into a table. But the indexes are kinda fked up. When I use the following (psuedo)code:
...
<<print headers and stuff>>
for ( $i = 0; $i < count( $array ); i++) {
$itemArray = $array[i];
for ( $j = 0; $j < count( $itemArray; j++) {
$innerItem = $itemArray[j];
echo <<tr start + both indexes in td>>
foreach ($innerItem as $spec) {
echo <<td with item>>
}
echo <<tr stop>>
}
}
In this example I am using i as index for the outer array and j as an index for the inner array (pretty obvious).
The result I am getting from this is as follows:
| index i | index j | title1 | title2 |
| 0 | 0 | | |
| 1 | 0 | | |
| 2 | 0 | | |
| ... | ... | | |
Whilst I would expect:
| index i | index j | title1 | title2 |
| 0 | 0 | | |
| 0 | 1 | | |
| 1 | 0 | | |
| 1 | 1 | | |
| 1 | 2 | | |
| 2 | 0 | | |
| ... | ... | | |
The (original) full code is:
echo "<h1>Combat analysis</h1>";
echo '<table cellspacing="0" cellpadding="4" border="1"><tbody>';
echo "<tr><td>#Mon</td><td>#Att</td><td>DungLVL</td><td>CharLVL</td><td>Health</td><td>Weapon</td><td>No. potions</td></tr>";
for ($battleIndex = 0; $battleIndex < count($this->combatLog); $battleIndex++) {
$battle = $this->combatLog[$battleIndex];
for ($attackIndex = 0; $attackIndex < sizeof($battle); $attackIndex++) {
$attack = $battle[$attackIndex];
echo "<tr><td>" . $battleIndex . "</td><td>" . $attackIndex . "</td>";
foreach ($attack as $stat) {
echo "<td>" . $stat . "</td>";
}
echo "</tr>";
}
}
echo "</tbody></table>";
What is going wrong?
Tested your code and runs as expected. You should do a echo '<pre>'.print_r($this->combatLog).'</pre>'; and debug the array contents.
Also I would recommend you the following:
1) You can use foreach instead of for, example: foreach ($this->combatLog as $battleIndex => $battle)
2) If you're not sure that a array contains values you should first do a: if (is_array($this->combatLog) && count($this->combatLog) > 0)
3) For simplicity and code maintenance I would first loop the multi-dimensional array and turn it into a one dimension called $attacks containing a array per each attack indexed by keys that you can recognize, ej:
$attacks=array();
$attacks[]=array(
'Mon'=>$battleIndex,
'Att'=>$attackIndex,
'DungLVL'=>isset($stat[0])?$stat[0]:null,
'CharLVL'=>isset($stat[1])?$stat[1]:null,
'Health'=>isset($stat[2])?$stat[2]:null,
'Weapon'=>isset($stat[3])?$stat[3]:null,
'Potions'=>isset($stat[4])?$stat[4]:null,
);
Then you could define some columns for example:
$columns=array(
'Mon',
'Att',
'DungLVL',
'CharLVL',
'Health',
'Weapon',
'Potions',
);
Then print the table header like this:
echo '<tr>';
foreach ($columns as $column) {
echo '<td>'.$column.'</td>';
}
echo '</tr>';
And print rows like this:
foreach ($attacks as $attack) {
echo '<tr>';
foreach ($columns as $column) {
echo '<td>'.$attack[$column].'</td>';
}
echo '</tr>';
}

Putting a row in the table at each 4 image using php?

This is what I want to happen:
------------ ------------ ------------ ------------
| | | | | | | |
| image | | image | | image | | image |
| | | | | | | |
------------ ------------ ------------ ------------
Name Name Name Name
------------ ------------ ------------ ------------
| | | | | | | |
| image | | image | | image | | image |
| | | | | | | |
------------ ------------ ------------ ------------
Name Name Name Name
But this is what's happening:
------------ ------ ------------ ------ ------------ ------------
| | |name| | | |name| | | | |
| image | | | | image | | | | image | | image |
| | | | | | | | | | | |
------------ ------ ------------ ------ ------------ ------------
All of them are just in one row
Here is the code i game using right now
echo"<table border=1>";
while ($row = mysql_fetch_array($content))
{
echo "<td><img src='".$row['image']."' width='100'></td>";
echo"<td>" . $row['name'] . "</td>";
}
echo"</table>";
There might be 8 images at each forth image should be a new Line and under each image should be the name
What am I doing wrong?
Here is what you want to do. It supports any number of rows and outputs 4 at a time. If there are 15 items for example, it outputs 4 in first three rows and 3 in the last one.
echo"<table border=1>";
$images = array();
$names = array();
while ($row = mysql_fetch_array($content))
{
$images[] = $row['image'];
$names[] = $row['name'];
}
while(!empty($images))
{
echo "<tr>";
foreach($images as $count=>$image)
{
echo "<td><img src='".$image."' width='100'></td>";
if($count==3)
{
$images = array_slice($images, 4);
break;
}
}
echo "</tr><tr>";
foreach($names as $count=>$name)
{
echo"<td>" . $name . "</td>";
if($count==3)
{
$names = array_slice($names, 4);
break;
}
}
echo "</tr>";
}
echo"</table>";
Here is a shorter version which does the same:
echo"<table border=1>";
//get images and names in two arrays
$images = array();
$names = array();
while ($row = mysql_fetch_array($content))
{
$images[] = "<img src='".$row['image']."' width='100'>";
$names[] = $row['name'];
}
while(!empty($images))
{
//output images
foreach(array($images, $names) as $items)
{
echo "<tr>";
foreach($items as $key=>$item)
{
echo "<td>$item</td>";
//output only four of them
if($key==3)
{
break;
}
}
echo "</tr>";
}
//remove the first four images from $images because they're already printed
$images = array_slice($images, 4);
$names = array_slice($names, 4);
}
echo"</table>";
It's a little crude but it should work
// store the cells in arrays instead of echoing them
$images=$names=array();
while ($row = mysql_fetch_array($content)){
$images[]="<td><img src='".$row['image']."' width='100'></td>";
$names[]="<td>" . $row['name'] . "</td>";
}
// split them into 4 each. This will give $image_cells[0] as an array with the first 4 images
// and $image_cells[1] containing the latter 4
$image_cells=array_chunk($images, 4);
// same with $names
$name_cells=array_chunk($names, 4);
// echo the table
echo"<table border=1>";
// echo a table row, concat the cells stored as an array to a string using implode
echo '<tr>'. implode('', $image_cells[0]).'</tr>';
// and again but using $name_cells[0] which is the first 4 names
echo '<tr>'. implode('', $name_cells[0]).'</tr>';
// second set of images
echo '<tr>'. implode('', $image_cells[1]).'</tr>';
// second set of names
echo '<tr>'. implode('', $name_cells[1]).'</tr>';
echo"</table>";

PHP display images from column value

Table
+-----+--------+---------+
| ID | Name | Images |
+-----+--------+---------+
| 001 | John | 5 |
| 002 | Mark | 3 |
+-----+--------+---------+
i would like to display like this
Jon, 001-1.jpg | 001-2.jpg | 001-2.jpg | 001-3.jpg | 001-4.jpg | 001-5.jpg |
Mark, 002-1.jpg | 002-2.jpg | 002-2.jpg | 002-3.jpg |
the images value on database table will be the number of images return to create images link
You can use this though. Didn't know why you found it difficult.
$c = 0
while (false !== ($data = fetch_array_as_row_function()))
{
echo "<tr>";
echo "<td>", $data["name"], "</td>";
for ($i = 0; $i < $data["images"]; $i++)
echo "<td>00", $c,"-", $i, "</td>";
echo "</tr>";
}
Here, the function fetch_array_as_row_function() is something equivalent to what mysql_fetch_array() does.

Category Hierarchy (PHP/MySQL)

I am trying to get my all categories and sub-categories from MySQL database in a hierarchy:
My result should be like that (just example):
Cat A
Sub-Cat 1
Sub_Sub_Cat 1
Sub_Sub_Cat 2
Sub_Cat 2
Cat B
Cat C
...
MySQL code:
CREATE TABLE IF NOT EXISTS `categories` (
`category_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'for sub-categories'
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Simply, how can get it in a hirarchy with PHP codes?
When using an adjacency list model, you can generate the structure in one pass.
Taken from One Pass Parent-Child Array Structure (Sep 2007; by Nate Weiner):
$refs = array();
$list = array();
$sql = "SELECT item_id, parent_id, name FROM items ORDER BY name";
/** #var $pdo \PDO */
$result = $pdo->query($sql);
foreach ($result as $row)
{
$ref = & $refs[$row['item_id']];
$ref['parent_id'] = $row['parent_id'];
$ref['name'] = $row['name'];
if ($row['parent_id'] == 0)
{
$list[$row['item_id']] = & $ref;
}
else
{
$refs[$row['parent_id']]['children'][$row['item_id']] = & $ref;
}
}
From the linked article, here's a snippet to create a list for output. It is recursive, if there a children for a node, it calls itself again to build up the subtree.
function toUL(array $array)
{
$html = '<ul>' . PHP_EOL;
foreach ($array as $value)
{
$html .= '<li>' . $value['name'];
if (!empty($value['children']))
{
$html .= toUL($value['children']);
}
$html .= '</li>' . PHP_EOL;
}
$html .= '</ul>' . PHP_EOL;
return $html;
}
Related Question:
How to obtain a nested HTML list from object's array recordset?
I have a new idea I think it will be nice.
The idea is this:
in category_parent column we will insert a reference to all parents of this node.
+----+----------------------+-----------------+
| id | category_name | hierarchy |
+----+----------------------+-----------------+
| 1 | cat1 | 1 |
+----+----------------------+-----------------+
| 2 | cat2 | 2 |
+----+----------------------+-----------------+
| 3 | cat3 | 3 |
+----+----------------------+-----------------+
| 4 | subcat1_1 | 1-4 |
+----+----------------------+-----------------+
| 5 | subcat1_2 | 1-5 |
+----+----------------------+-----------------+
| 6 | subsubcat1_1 | 1-4-6 |
+----+----------------------+-----------------+
| 7 | subsubcat1_2 | 1-4-7 |
+----+----------------------+-----------------+
| 8 | subsubcat1_3 | 1-4-8 |
+----+----------------------+-----------------+
| 9 | subsubcat1_3_1 | 1-4-8-9 |
+----+----------------------+-----------------+
| 10 | subsubcat1_3_2 | 1-4-8-10 |
+----+----------------------+-----------------+
| 11 | subsubcat1_3_1_1 | 1-4-8-9-11 |
+----+----------------------+-----------------+
| 12 | subsubsubcat1_3_1_1 | 1-4-8-9-12 |
+----+----------------------+-----------------+
| 13 | subsubsubcat1_3_1_2 | 1-4-8-9-11-13 |
+----+----------------------+-----------------+
| 14 | subsubsubcat1_2_1_3 | 1-4-8-9-11-14 |
+----+----------------------+-----------------+
if you look at my updated table you will notice that every record has an link to its parents, not only the direct one, But also all of parents.
And for that job I made some modification to insert to be:
Insert into table_name (category_name, hierarchy) values ('new_name', (concat(parent_hierarch, '-', (SELECT Auto_increment FROM information_schema.tables WHERE table_name='table_name'))))
Now lets make your desired queries:
1- all sub categories of cars:
select * from table_name where hierarchy like '1-%'
2- if you need all parent of BLACK you simply type:
select * from table_name where hierarchy = '1-4-8-9' or hierarchy = '1-4-8' or hierarchy = '1-4' or hierarchy = '1'
(you can build that query from php, splitting hierarchy field at '-' char)
3- To see all categories, with level and direct parent:
select *, SUBSTR(hierarchy, 1, (LENGTH(hierarchy) - LENGTH(id) - 1)) as parent, LENGTH(hierarchy) - LENGTH(REPLACE(hierarchy, '-', '')) as level From table_name
+----+----------------------+-----------------+-----------+--------+
| id | category name | hierarchy | parent | level |
+----+----------------------+-----------------+-----------+--------+
| 1 | cat1 | 1 | | 0 |
+----+----------------------+-----------------+-----------+--------+
| 2 | cat2 | 2 | | 0 |
+----+----------------------+-----------------+-----------+--------+
| 3 | cat3 | 3 | | 0 |
+----+----------------------+-----------------+-----------+--------+
| 4 | subcat1_1 | 1-4 | 1 | 1 |
+----+----------------------+-----------------+-----------+--------+
| 5 | subcat1_2 | 1-5 | 1 | 1 |
+----+----------------------+-----------------+-----------+--------+
| 6 | subsubcat1_1 | 1-4-6 | 1-4 | 2 |
+----+----------------------+-----------------+-----------+--------+
| 7 | subsubcat1_2 | 1-4-7 | 1-4 | 2 |
+----+----------------------+-----------------+-----------+--------+
| 8 | subsubcat1_3 | 1-4-8 | 1-4 | 2 |
+----+----------------------+-----------------+-----------+--------+
| 9 | subsubcat1_3_1 | 1-4-8-9 | 1-4-8 | 3 |
+----+----------------------+-----------------+-----------+--------+
| 10 | subsubcat1_3_2 | 1-4-8-10 | 1-4-8 | 3 |
+----+----------------------+-----------------+-----------+--------+
| 11 | subsubcat1_3_1_1 | 1-4-8-9-11 | 1-4-8-9 | 4 |
+----+----------------------+-----------------+-----------+--------+
| 12 | subsubsubcat1_3_1_1 | 1-4-8-9-12 | 1-4-8-9 | 4 |
+----+----------------------+-----------------+-----------+--------+
| 13 | subsubsubcat1_3_1_2 | 1-4-8-9-11-13 |1-4-8-9-11 | 5 |
+----+----------------------+-----------------+-----------+--------+
| 14 | subsubsubcat1_2_1_3 | 1-4-8-9-11-14 |1-4-8-9-11 | 5 |
+----+----------------------+-----------------+-----------+--------+
This is a new idea and need some improvement.
Try the following code
//connect to mysql and select db
$conn = mysqli_connect('localhost', 'user', 'password','database');
if( !empty($conn->connect_errno)) die("Error " . mysqli_error($conn));
//call the recursive function to print category listing
category_tree(0);
//Recursive php function
function category_tree($catid){
global $conn;
$sql = "select * from category where parent_id ='".$catid."'";
$result = $conn->query($sql);
while($row = mysqli_fetch_object($result)):
$i = 0;
if ($i == 0) echo '<ul>';
echo '<li>' . $row->cat_name;
category_tree($row->id);
echo '</li>';
$i++;
if ($i > 0) echo '</ul>';
endwhile;
}
//close the connection
mysqli_close($conn);
?>
More...
#Amnon Your code works perfectly. Just tested it with CodeIgniter and it worked like a charm. Here's the working code if anyone needs it:
<?php
function disTree($all_cats) {
$tree = array();
foreach ($all_cats as $cat)
{
$pid = $cat->parent_id;
$id = $cat->cat_id;
$name = $cat->cat_name;
// Create or add child information to the parent node
if (isset($tree[$pid]))
// a node for the parent exists
// add another child id to this parent
$tree[$pid]["children"][] = $id;
else
// create the first child to this parent
$tree[$pid] = array("children"=>array($id));
// Create or add name information for current node
if (isset($tree[$id]))
// a node for the id exists:
// set the name of current node
$tree[$id]["name"] = $name;
else
// create the current node and give it a name
$tree[$id] = array( "name"=>$name );
}
return $tree;
}
function toUL($tree, $id, $html){
$html .= '<ul>'.PHP_EOL;
if (isset($tree[$id]['name']))
$html .= '<li>' . $tree[$id]['name'];
if (isset($tree[$id]['children']))
{
$arChildren = &$tree[$id]['children'];
$len = count($arChildren);
for ($i=0; $i<$len; $i++) {
$html .= toUL($tree, $arChildren[$i], "");
}
$html .= '</li>'.PHP_EOL;
}
$html .= '</ul>'.PHP_EOL;
return $html;
}
$tree = disTree($all_cats);
// Display the tree
echo toUL($tree, 0, "");
?>
The only thing I changed was adding my own array ($all_cats).
There's another way to achieve the same effect which I find a bit easier to follow (without the reference trick). You build the tree by adding the relevant information to the current node and to its parent (assume the foreach iterates over the returned rows from the SQL query):
$tree = array();
foreach ($query->result() as $row)
{
$pid = $row->parent_id;
$id = $row->id;
$name = $row->name;
// Create or add child information to the parent node
if (isset($tree[$pid]))
// a node for the parent exists
// add another child id to this parent
$tree[$pid]["children"][] = $id;
else
// create the first child to this parent
$tree[$pid] = array("children"=>array($id));
// Create or add name information for current node
if (isset($tree[$id]))
// a node for the id exists:
// set the name of current node
$tree[$id]["name"] = $name;
else
// create the current node and give it a name
$tree[$id] = array( "name"=>$name );
}
return $tree;
and to display the tree:
function toUL($tree, $id, $html){
$html .= '<ul>'.PHP_EOL;
if (isset($tree[$id]['name']))
$html .= '<li>' . $tree[$id]['name'];
if (isset($tree[$id]['children']))
{
$arChildren = &$tree[$id]['children'];
$len = count($arChildren);
for ($i=0; $i<$len; $i++) {
$html .= toUL($tree, $arChildren[$i], "");
}
$html .= '</li>'.PHP_EOL;
}
$html .= '</ul>'.PHP_EOL;
return $html;
}
// Display the tree
echo toUL($tree, 0, "");

Print results of a SELECT query as preformatted text in PHP?

I'm looking for an easy and quick way to print out the results of a MySQL SELECT query in PHP as preformatted text. What I would like is to be able to pass a query object to a function and get a printout of the recordset like the command line MySQL client does when running SELECT statements.
Here is an example of how I want it to look (i.e. ASCII):
+----+-------------+
| id | countryCode |
+----+-------------+
| 1 | ES |
| 2 | AN |
| 3 | AF |
| 4 | AX |
| 5 | AL |
| 6 | DZ |
| 7 | AS |
| 8 | AD |
| 9 | AO |
| 10 | AI |
+----+-------------+
It's basically for a generic import script, I am doing a SELECT query and want to display the results to the user for confirmation.
sprintf is your friend, if you must have a non-HTML fixed width output.
ETA:
//id: integer, max width 10
//code: string max width 2
$divider=sprintf("+%-10s+%-13s+",'-','-');
$lines[]=$divider;
$lines[]=sprintf("|%10s|%13s|",'id','countryCode'); //header
$lines[]=$divider;
while($line=$records->fetch_assoc()) {
//store the formatted output
$lines[]=sprintf("| %10u | %2.2s |", $line['id'],$line['code']);
}
$table=implode("\n",$lines);
echo $table;
If you want to print out immediately instead of storing the results, use printf instead- same syntax. There is a reasonable PHP (s)printf tutorial here.
function formatResults($cols, $rows) {
echo'<table>';
echo '<tr>';
foreach ($cols as $v) {
echo '<th>' . $v['field'] . '</th>';
}
echo '</tr>';
foreach ($rows as $sRow) {
echo '<tr>';
foreach ($sRow as $v) {
echo "<td>$v</td>";
}
echo '</tr>';
}
echo '</table>';
}
$qry = $pdo->query('DESCRIBE table');
$cols = $qry->fetchAll(PDO::FETCH_ASSOC);
$pdo->query('SELECT * FROM table');
$rows = $qry->fetchAll(PDO::FETCH_ASSOC);
formatResults($cols, $rows);
Untested but should work.
Edit: Missed ['field'] index ;)

Categories