I have html table and I want to make array from that table
$html = '<table>
<tr>
<td>satu</td>
<td>dua</td>
</tr>
<tr>
<td>tiga</td>
<td>empat</td>
</tr>
</table>
My array must look like this
array(
array(
"satu",
"dua",
),
array(
"tiga",
"empat",
)
)
I have tried the below code but could not get the array as I need
$crawler = new Crawler();
$crawler->addHTMLContent($html);
$row = array();
$tr_elements = $crawler->filterXPath('//table/tr');
foreach ($tr_elements as $tr) {
// ???????
}
$table = $crawler->filter('table')->filter('tr')->each(function ($tr, $i) {
return $tr->filter('td')->each(function ($td, $i) {
return trim($td->text());
});
});
print_r($table);
The above example will give you a multidimensional array where the first layer are the table lines "tr" and the second layer are the table columns "td".
EDIT
If you got nested tables, this code will flatten them out nicely into a single dimension array.
$html = 'MY HTML HERE';
$crawler = new Crawler($html);
$flat = function(string $selector) use ($crawler) {
$result = [];
$crawler->filter($selector)->each(function ($table, $i) use (&$result) {
$table->filter('tr')->each(function ($tr, $i) use (&$result) {
$tr->filter('td')->each(function ($td, $i) use (&$result) {
$html = trim($td->html());
if (strpos($html, '<table') !== FALSE) return;
$iterator = $td->getIterator()->getArrayCopy()[0];
$address = $iterator->getNodePath();
if (!empty($html)) $result[$address] = $html;
});
});
});
return $result;
};
// The selector gotta point to the most outwards table.
print_r($flat('#Prod fieldset div table'));
$html = '<table>
<tr>
<td>satu</td>
<td>dua</td>
</tr>
<tr>
<td>tiga</td>
<td>empat</td>
</tr>
</table>';
$crawler = new Crawler();
$crawler->addHTMLContent($html);
$rows = array();
$tr_elements = $crawler->filterXPath('//table/tr');
// iterate over filter results
foreach ($tr_elements as $i => $content) {
$tds = array();
// create crawler instance for result
$crawler = new Crawler($content);
//iterate again
foreach ($crawler->filter('td') as $i => $node) {
// extract the value
$tds[] = $node->nodeValue;
}
$rows[] = $tds;
}
var_dump($rows );exit;
will display
array
0 =>
array
0 => string 'satu'
1 => string 'dua'
1 =>
array (size=2)
0 => string 'tiga'
1 => string 'empat'
Related
I am trying to get tracking information from amazon using provided url
https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302
I am getting response using file_get_contents() function in php,
what I want is to show only that part of the response which contains the tracking information as an output of my php script and eliminate/hide all the unnecessary content from file_get_contents() response.
One way to do what you're looking for is use DomDocument to filter out the json data in the source ($file) and then use a recursive function to get the elements you need.
You can set the elements you need using an array, $filter. In this example we've taken a sample of some of the available data, i.e. :
$filter = [
'orderId', 'shortStatus', 'promiseMessage',
'lastTransitionPercentComplete', 'lastReachedMilestone', 'shipmentId',
];
The code
<?php
$filename = 'https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302';
$file = file_get_contents($filename);
$trackingData = []; // store for order tracking data
$html = new DOMDocument();
#$html->loadHTML($file);
foreach ($html->getElementsByTagName('script') as $a) {
$data = $a->textContent;
if (stripos($data, 'shortStatus') !== false) {
$trackingData = json_decode($data, true);
break;
}
}
// set the items we need
$filter = [
'orderId', 'shortStatus', 'promiseMessage',
'lastTransitionPercentComplete', 'lastReachedMilestone', 'shipmentId',
];
// invoke recursive function to pick up the data items specified in $filter
$result = getTrackingData($filter, $trackingData);
echo '<pre>';
print_r($result);
echo '</pre>';
function getTrackingData(array $filter, array $data, array &$result = []) {
foreach($data as $key => $value) {
if(is_array($value)) {
getTrackingData($filter, $value, $result);
} else {
foreach($filter as $item) {
if($item === $key) {
$result[$key] = $value;
}
}
}
}
return $result;
}
Output:
Array
(
[orderId] => 203-2171364-3066749
[shortStatus] => IN_TRANSIT
[promiseMessage] => Arriving tomorrow by 9 PM
[lastTransitionPercentComplete] => 92
[lastReachedMilestone] => SHIPPED
[shipmentId] => 23796758607302
)
Try this
<?php
$filename = 'https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302';
$file = file_get_contents($filename);
$html = new DOMDocument();
#$html->loadHTML($file);
foreach($html->getElementsByTagName('span') as $a) {
$property=$a->getAttribute('id');
if (strpos($property , "primaryStatus"))
print_r($property);
}
?>
It should show "Arriving tomorrow by 9 PM" status.
I might be punching slightly above my weight here or maybe its a really simple problem with a simple solution.
MY PROBLEM
I cant access array key values in foreach()
When creating the array in a function it seems that the array is duplicating, does a double iteration when created(as you can see in image below)
STEP 1: Array Creation
$results = $stmnt->fetchAll();
if ($stmnt->rowCount() > 0) {
$totalCorrectPicks = 0;
//--->HERE ARRAY KEYS ARE CREATED FROM QUERYING DB
foreach ($results as $index => $result) {
$returnResult = array('picked' => $result['team'], 'homeScore' => $result['homeScore'], 'awayScore' => $result['awayScore'], 'homeTeam' => $result['homeTeam'],
'awayTeam' => $result['awayTeam'], 'score' => $result['score']);
}//end foreach
//------> HERE ELEMENTS GETS APPENDED TO ARRAY
$pickedTeam = $result['team'];
if ($result['homeScore'] > $result['awayScore']) {
$matchOutcome = $result['homeTeam'];
$matchScore = $result['homeScore'];
$returnResults['matchOutcome'] = $matchOutcome;
$returnResults['matchScore'] = $matchScore;
}
if ($result['awayScore'] > $result['homeScore']) {
$matchOutcome = $result['awayTeam'];
$matchScore = $result['awayScore'];
$returnResults['matchOutcome'] = $matchOutcome;
$returnResults['matchScore'] = $matchScore;
}
if ($pickedTeam === $matchOutcome) {
$totalCorrectPicks++;
$margin = abs($matchScore - $result['points']);
//INDEX WILL START AT 0 SO WE ADD ONE TO $INDEX
$nrGames = $index + 1;
$returnResults['totatlCorrectPicks'] = $totalCorrectPicks;
$returnResults['margin'] = $margin;
$returnResults['nrGames'] = $nrGames;
}
elseif ($pickedTeam !== $matchOutcome) {
$margin = 'wrongPick';
$returnResults['margin'] = $margin;
}
}
}
if(isset($returnResults)){
print_r($returnResults);
return $returnResults;
}
return false;
}
STEP 2 Calling function and using array; leads to illegal string offset
<?php $picks = checkUserPicks('5');
foreach ($picks as $index => $pick){
?>
<tr>
<td>
<?php echo $pick['picked']; ?>
</td>
<td>
<?php echo $pick['matchOutcome']; ?>
</td>
<td>
<?php echo $pick['margin']; ?>
</td>
</tr>
<?php } ?>
NOTE: you can see the array value in the image posted above.
Questions
1) Why does it seem like the array is duplicated (see image)?
2) How can I fix the illegal string offset and what causes it?
Thanks
UPDATE
New Array Structure after removing [] from $returnResults[]
After end of foreach loop, matchOutcome, matchScore, etc are appended to the array. Shouldn't it be inside the loop?
If you are expecting more than one row, then you need to create array by maintaining its index as follows:
$returnResults = array(); // Initialize array
foreach ($results as $index => $result) {
$returnResults[$index] = array('picked' => $result['team'], 'homeScore' => $result['homeScore'],
'awayScore' => $result['awayScore'], 'homeTeam' => $result['homeTeam'],
'awayTeam' => $result['awayTeam'], 'score' => $result['score']);
//------> HERE ELEMENTS GETS APPENDED TO ARRAY
$pickedTeam = $result['team'];
if ($result['homeScore'] > $result['awayScore']) {
$matchOutcome = $result['homeTeam'];
$matchScore = $result['homeScore'];
$returnResults[$index]['matchOutcome'] = $matchOutcome;
$returnResults[$index]['matchScore'] = $matchScore;
}
.
.
elseif ($pickedTeam !== $matchOutcome) {
$margin = 'wrongPick';
$returnResults[$index]['margin'] = $margin;
}
}//end foreach
question: In my code I want remove header tr html tag (witch attribute is<tr class='background1'> )
urL http://www.rayansaba.com/index.php?ukey=pricelist
In following code is if condition to avoid headers but I don't no way cant remove.
$table_rows = $xpath->query("//div[#class='cpt_maincontent']/center/table/tr"); // target the row (the browser rendered <tbody>, but actually it really doesnt have one)
if($table_rows->length <= 0) { // exit if not found
echo 'no table rows found';
exit;
}
$i = 0;
$trlength = count($table_rows);
foreach($table_rows as $tr){
$row = $tr->childNodes;
if($row->item(0)->tagName!='<tr class="background1"></tr>') { // avoid headers
$data[] = array(
'Name' => trim($row->item(0)->nodeValue),
'Price' => trim($row->item(2)->nodeValue),
);
}
}
Actually, you can just add it inside the xpath query excluding those rows with background, then extract the values and push the node values accordingly. Example:
$dom = new DOMDocument;
#$dom->loadHTMLFile('http://www.rayansaba.com/index.php?ukey=pricelist');
$xpath = new DOMXpath($dom);
$table_rows = $xpath->query("//div[#class='cpt_maincontent']/center/table/tr[not(#class)]");
$data = array();
foreach($table_rows as $tr) {
if($tr->getElementsByTagName('td')->length > 2) {
$name = trim($tr->getElementsByTagName('td')->item(0)->nodeValue);
$price = trim($tr->getElementsByTagName('td')->item(2)->nodeValue);
$data[] = array('Name' => $name, 'Price' => $price);
}
}
echo '<pre>', print_r($data, 1), '</pre>';
I have mock fantasy football form that creates data in an external text file and I have everything working, I have just run into one problem. Can someone show me how I can sort the players by their number (largest on top) and then highlight (in red) the whole row of the player that has had the most points?
Here is my form file:
<!doctype html public "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<title>Fantasy Football</title>
</head>
<body>
<form action="team.php" method="POST">
<table border="1">
<tr><td>Player Name</td><td><input type="text" name="name"</td></tr>
<tr><td>Position</td><td><input type="text" name="position"</td></tr>
<tr><td>Number</td><td><input type="text" name="number"</td></tr>
<tr><td>Team</td><td><input type="text" name="team"</td></tr>
<tr><td>Points per game</td><td><input type="text" name="points"</td></tr>
<tr><td colspan="2" align="center"><input type="submit"></td></tr>
</table>
</form>
</body>
</html>
And here is the return data:
<?php
$name = $_POST['name'];
$team = $_POST['team'];
$number = $_POST['number'];
$position = $_POST['position'];
$points = $_POST['points'];
$DOC_ROOT = $_SERVER['DOCUMENT_ROOT'];
# $fp = fopen("$DOC_ROOT/../php/football.txt","ab");
if(!$fp) {
echo 'Error: Cannot open file.';
exit;
}
fwrite($fp, $name."|".$team."|".$number."|".$position."|".$points."\n");
?>
<?php
$DOC_ROOT = $_SERVER['DOCUMENT_ROOT'];
$players = file("$DOC_ROOT/../php/football.txt");
echo "<table border='2'>";
echo "<tr> <td>Name</td> <td>Team</td> <td>number</td> <td>Position</td> <td>Points</td> </tr>";
for($i = 0; $i < sizeof($players); $i++) {
list($name,$team,$number,$position,$points) = explode('|', $players[$i]);
echo '<tr><td>'.$name.'</td><td>'.$team.'</td><td>'.$number.'</td>
<td>'.$position.'</td><td>'.$points.'</td></tr>';
}
echo '</table>';
?>
Not really good at inserting bits an pieces of code, so if you could, can you tell me exactly where to put whatever you can give me?
Update:
Is this where I needed to put everything? The way it is now, when I submit my form I don't see anything! Obviously I did something wrong, so I'm open to suggestions!
<?php
function sort_player_array( $array, $key, $asc = true) {
$result = array();
$values = array();
foreach ($array as $id => $value) {
$values[$id] = isset($value[$key]) ? $value[$key] : '';
}
if ($asc) {
asort($values);
}
else {
arsort($values);
}
foreach ($values as $key => $value) {
$result[$key] = $array[$key];
}
return $result;
}
?>
<?php
$name = $_POST['name'];
$team = $_POST['team'];
$number = $_POST['number'];
$position = $_POST['position'];
$points = $_POST['points'];
$DOC_ROOT = $_SERVER['DOCUMENT_ROOT'];
# $fp = fopen("$DOC_ROOT/../php/football.txt","ab");
if(!$fp) {
echo 'Error: Cannot open file.';
exit;
}
?>
<?php
fwrite($fp, $name."|".$team."|".$number."|".$position."|".$points."\n");
$players = file("$DOC_ROOT/../php/football.txt");
$player_array = array();
foreach($players AS $player)
{
list($name,$team,$number,$position,$points) = explode('|', $players[$i]);
$player_array[] = array('name' => $name,
'number' => $number,
'position' => $position,
'points' => $points,
);
}
$sorted_players = sort_player_array($player_array, 'number', true);
foreach( $sorted_players AS $player )
{
echo '<tr><td>'.$player[name].'</td><td>'.$player[team].'</td><td>'
.$player[number].'</td><td>'.$player[position].'</td><td>'.$player[points].'</td></tr>';
} ?>
first of all you are programming in PHP, use COUNT() instead of SIZEOF().
sizeof() is an alias of count() and might be removed as php evolves.
We need a function for sorting the array:
function sort_player_array( $array, $key, $asc = true) {
$result = array();
$values = array();
foreach ($array as $id => $value) {
$values[$id] = isset($value[$key]) ? $value[$key] : '';
}
if ($asc) {
asort($values);
}
else {
arsort($values);
}
foreach ($values as $key => $value) {
$result[$key] = $array[$key];
}
return $result;
}
next build an array with php holding your data, then sort it .
$players = file("$DOC_ROOT/../php/football.txt");
$player_array = array();
foreach($players AS $player)
{
list($name,$team,$number,$position,$points) = explode('|', $players[$i]);
$player_array[] = array('name' => $name,
'number' => $number,
'position' => $position,
'points' => $points,
);
}
We sort the array as you requested by number, but any key is possible. also you can set ASC or DESC with the third variable
$sorted_players = sort_player_array($player_array, 'number', true);
foreach( $sorted_players AS $player )
{
echo '<tr><td>'.$player[name].'</td><td>'.$player[team].'</td><td>'.$player[number].'</td><td>'.$player[position].'</td><td>'.$player[points].'</td></tr>';
}
Seems like you need some kind of sorting algorithm function for $players. There are different kinds, and you can find many by googling "sorting algorithms", or you can write one yourself if you feel like "reinventing the wheel". Doing one yourself does make for good practice/fun :D
Here's a link to a wiki on bubble sort, probably the most common basic sorting and would help in your situation.
Prepare an array $playerData, which contains all player records and use their numbers as key. Then use ksort():
ksort( $playerData );
While preparing the $playerData, keep a variable $maxPoints and $mapPointsPlayerNumber and check each player's data against these values. Update them if current player's point is higher than $maxPoints.
I think you should be able to create arrays with the list function. Something like this:
//set array variables
for($i = 0; $i < sizeof($players); $i++) {
list($name[],$team[],$number[],$position[],$points[]) = explode('|', $players[$i]);
}
//sort all arrays by the number, in descending order
array_multisort($number, $position, $name, $team, $points, SORT_DESC);
//set the highest points to mostPoints variable
var mostPoints = max($points);
//Output table rows
for($i = 0; $i < sizeof($players); $i++) {
if($points[$i]==mostPoints){
//red background
echo '<tr style="background:#F44">';
}else{
echo '<tr>';
}
echo '<td>'.$name[$i].'</td><td>'.$team[$i].'</td><td>'.$number[$i].'</td><td>'.$position[$i].'</td><td>'.$points[$i].'</td></tr>';
}
I haven't tested this, so there may be a few things in there that I've missed, but it should work. See Array Multisort, and max functions. It may be better to assign a class to the red table row, instead of a style; that way you can alter the td tags; I think that's more browser-friendly. The CSS for that would be something like .redRow td {background:#F44} if you gave the tr the redRow class.
I have the following table: http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat
It is a currency exchange list and I need to extract some data from it. On left side of the table are currency ID numbers. Would it be possible to extract data from specified rows based on their IDs?
For example, from the table above, I want to extract currencies with IDs 978, 203, and 348.
Output should be:
EUR 104,2182
CZK 4,2747
HUF 38,7919
By looking at similar examples here, I came up with this: http://pastebin.com/hFZs1H7C
I need somehow to detect IDs and the print proper values... I'm noob when it comes to programming and I need your help.
<?php
$data = file_get_contents('http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat');
$dom = new domDocument;
#$dom->loadHTML($data);
$dom->preserveWhiteSpace = false;
$tables = $dom->getElementsByTagName('table');
$rows = $tables->item(1)->getElementsByTagName('tr');
foreach ($rows as $row) {
$cols = $row->getElementsByTagName('td');
foreach ($cols as $col) {
echo $col;
}
}
?>
Collecting the table data as array for later usage:
$dom = new DomDocument;
$dom->loadHtmlFile('http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat');
$xpath = new DomXPath($dom);
// collect header names
$headerNames = array();
foreach ($xpath->query('//table[#id="index:srednjiKursLista"]//th') as $node) {
$headerNames[] = $node->nodeValue;
}
// collect data
$data = array();
foreach ($xpath->query('//tbody[#id="index:srednjiKursLista:tbody_element"]/tr') as $node) {
$rowData = array();
foreach ($xpath->query('td', $node) as $cell) {
$rowData[] = $cell->nodeValue;
}
$data[] = array_combine($headerNames, $rowData);
}
print_r($data);
Output:
Array
(
[0] => Array
(
[ŠIFRA VALUTE] => 978
[NAZIV ZEMLJE] => EMU
[OZNAKA VALUTE] => EUR
[VAŽI ZA] => 1
[SREDNJI KURS] => 104,2182
)
...
)
Example usage:
foreach ($data as $entry) {
printf(
'%s %s' . PHP_EOL,
$entry['OZNAKA VALUTE'],
$entry['SREDNJI KURS']
);
}
You can use xpath and domdocument features of PHP to extract specific data from html(or xml.)
$src = new DOMDocument('1.0', 'utf-8');
$src->formatOutput = true;
$src->preserveWhiteSpace = false;
$content = file_get_contents("http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat");
#$src->loadHTML($content);
$xpath = new DOMXPath($src);
$values=$xpath->query('//td[ contains (#class, "tableCell") ]');
foreach($values as $value)
{
echo $value->nodeValue."<br />";
}
this will print innerHTML of every td element with class="tableCell".