I am Trying to fill my Excel sheet with the data i filtered through the methods i have made. For now i am getting a sheet but i only have only one row filled not the other it's not getting the data i provide it though my object
I am trying my sheet something similar to this sheet .
i am trying to write code in this part of code :
public function export($Sets,$disp_filter)
{
$objPHPExcel = new PHPExcel();
$objPHPExcel->getProperties()->setTitle("Offic excel Test Document");
$styleArray = array(
'font' => array(
'bold' => true,
'color' => array('rgb' => 'FF0000'),
'size' => 10,
'name' => 'Verdana'
));
$objPHPExcel->getActiveSheet()->getStyle('A1')->applyFromArray($styleArray);
$excel_out = array($this->outputSampleName($Sets));
// var_dump($excel_out);
// exit;
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Sample Size and Margin of Error');
$rowCount = 2;
foreach ($excel_out as $key=> $line)
{
$colCount = 'A';
$i=0;
// $line = array($Set['name']);
// $CT = $Set['crossTabs']['base'];
// $Moe = array($CT['sample']['moe']);
foreach($line as $col_value)
{
// var_dump($col_value);
// exit;
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $col_value[$i])
->getStyle($colCount.$rowCount)->applyFromArray($styleArray);
$colCount++;
}
$rowCount++;
$i++;
}
return $objPHPExcel;
}
protected function outputSampleName($Sets)
{
foreach ($Sets as $Set)
{
$CT = $Set['crossTabs']['base'];
$line = array(
$Set['name'],
$CT['sample']['moe'] . '%'
);
$excel_out []= $line;
}
return $excel_out;
}
when i see by var_dump($excel_out)
i have this data structure :
**Please suggest me something how can i get those percentage values in my next row in optimized way.
for now i can only loop through the sample[name] which are (enthusiasts, hunter, new shooters etc. )from that array. **
thanks in advance
Maybe because your array elements are arrays themselves, and you are trying to place these subarrays into cells.
Try setting each element of $line in separate cells:
foreach ($excel_out as $line)
{
$colCount = 'A';
$objPHPExcel->getActiveSheet()
->setCellValue('A'.$rowCount, $line[0])
->setCellValue('B'.$rowCount, $line[1])
->setCellValue('C'.$rowCount, $line[2])
->setCellValue('D'.$rowCount, $line[3])
->setCellValue('E'.$rowCount, $line[4]);
$colCount++;
$rowCount++;
}
Note that the first sub-array in $excel_out has only one element. You may want to store.
You could also use an inner loop to traverse through each $line.
EDIT:
After looking at the code in your answer.
Using inner loop:
oreach ($excel_out as $key=> $line)
{
$colCount = 'A';
$i = 0;
foreach($line as $col_value)
{
// var_dump($col_value);
// exit;
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $col_value[$i]);
//$objPHPExcel->getActiveSheet()->setCellValue('B'.$rowCount, $col_value[1]);
//$objPHPExcel->getActiveSheet()->setCellValue('C'.$rowCount, $col_value[2]);
//$objPHPExcel->getActiveSheet()->setCellValue('D'.$rowCount, $col_value[3]);
//$objPHPExcel->getActiveSheet()->setCellValue('E'.$rowCount, $col_value[4]);
//$objPHPExcel->getActiveSheet()->setCellValue('F'.$rowCount, $col_value[5]);
$colCount++;
$i++;
//$rowCount++;
}
$rowCount++;
// $colCount++;
}
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $line);
Seems like you're writing an array $line into a cell. Should you do a loop from 0 to count($line) to put each element into a cell?
Related
I have this partially working. I need to grab the data of each player, and present a variable for each "cricket" and "x01" games. I am able to grab the data from the top table, however the 2nd one is not showing any data in my code. I am probably missing something simple, but I can't figure it out.
I want the output to show like this. The part under the line break is what I am missing.
"Howard Hill": {
"name": "Howard Hill",
"team": "Team 2",
"ppd_01": "34.54",
"games_01": "153",
"wins_01": "999",
"assists_01": "69",
"sspre_01": "7.876",
"mpr_crk": "9.99",
"games_crk": "999",
"wins_crk": "999",
"assists_crk": "99",
"sspre_crk": "9.999"
}
Here is my code
<?php
ini_set('default_socket_timeout', 180); // 900 Seconds = 15 Minutes
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('http://freerdarts.com/past_stats/tues-2018-player-standings.html'));
$doc->strictErrorChecking = false;
$pre = [];
foreach ($doc->getElementsByTagName('table') as $table) {
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
$y = 0;
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($y > 7) {
unset($pre[$i]);
continue;
}
if (empty($text)) {
continue;
}
$pre[$i][] = $text;
$y++;
}
}
}
// normalise
$pstats = [];
foreach ($pre as $row) {
$pstats[$row[0]] = [
'name' => $row[0],
'team' => $row[1],
'ppd_01' => $row[2],
'games_01' => $row[3],
'wins_01' => $row[4],
'sspre_01' => $row[5],
];
}
echo '<pre>'.json_encode($pstats, JSON_PRETTY_PRINT).'</pre>';
//echo $pstats['Scott Sandberg']['01'];
?>
One problem you're facing is that you're not getting the proper table that needs parsing.
Take note there are multiple tables inside that page.
You need to point out inside the loop that you're skipping other tables in the HTML page and only choose to process the score report table, nothing else:
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
So after getting other tables out of the way, you can start processing the data inside the specific table results that you want to store.
Another thing to point out is you need to skip the headers inside the table. You don't need to anyways.
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
After that, its just a matter of looping on each <td>.
One gotcha on the tables is that one table has six 6 columns. Another one has 7 so first gather all <td> values. After gathering just unset it from the gathered data so that you have a uniform column layout structure. (I assume you're trying to skip out assists)
Here's the full code:
$pre = []; // initialize container
$keys = ['name', 'team', 'ppd', 'games', 'wins', 'sspre']; // keys needed to be used in the json
foreach ($doc->getElementsByTagName('table') as $table) { // loop all found tables
if (strpos($table->getAttribute('class'), 'report') === false) {
continue; // if its not the report table, skip
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) { // loop each row of report table
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = []; // initialize container for each row
foreach ($tr->childNodes as $td) { // loop each cell
$text = trim($td->nodeValue); //
if ($text === '') continue;
$row_values[] = $text;
}
// unset assist if this table has 7 columns
if (count($row_values) === 7) unset($row_values[5]);
$row_values = array_combine($keys, $row_values); // combine the keys and values
$pre[$row_values['name']] = $row_values; // push them inside
}
}
// finally encode in the end
echo json_encode($pre);
Here's the sample output
I have modified #Ghost code. Try below code.
<?php
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('http://freerdarts.com/past_stats/tues-2018-player-standings.html'));
$doc->strictErrorChecking = false;
$pre = [];
$keys = ['name', 'team', 'ppd', 'games', 'wins', 'sspre'];
$keys2 = ['name', 'mpr', 'games', 'wins','assists', 'sspre'];
foreach ($doc->getElementsByTagName('table') as $k => $table) {
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = [];
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($text === '') continue;
$row_values[] = $text;
}
if($k == 1 ){
$row_values = array_combine($keys, $row_values);
}elseif($k == 2 ){
unset($row_values[1]);
$row_values = array_combine($keys2, $row_values);
}
$pre[$row_values['name']][] = $row_values;
}
}
$new_arr = [];
foreach($pre as $name => $row){
$new_arr[$name] = [
"name"=> $name,
"team"=> $row[0]['team'],
"ppd_01" => $row[0]['ppd'],
"games_01" => $row[0]['games'],
"wins_01" => $row[0]['wins'],
"sspre_01" => $row[0]['sspre'],
"mpr_crk" => $row[1]['mpr'],
"games_crk" => $row[1]['games'],
"wins_crk" => $row[1]['wins'],
"assists_crk" => $row[1]['assists'],
"sspre_crk" => $row[1]['sspre']
];
}
echo '<pre>'.json_encode($new_arr, JSON_PRETTY_PRINT).'</pre>';
Here is sample output
https://www.tehplayground.com/Du5rId3iRx3NH6UL
It seems to me that you want to combine the x01 table values with the crk table values under the same name. Here is the code that I think you are looking for with an example.
$x01 = [];
$crk = [];
$keys_01 = ['name', 'team', 'ppd_01', 'games_01', 'wins_01', 'sspre_01'];
$keys_crk = ['name', 'team', 'mpr_crk', 'games_crk', 'wins_crk', 'assists_crk', 'sspre_crk'];
$table_num = 1;
foreach ($doc->getElementsByTagName('table') as $table) {
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = [];
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($text === '') continue;
$row_values[] = $text;
}
// build x01 array
if ($table_num === 1) {
$row_values = array_combine($keys_01, $row_values);
$x01[$row_values['name']] = $row_values;
// build crk array
} else {
$row_values = array_combine($keys_crk, $row_values);
$crk[$row_values['name']] = $row_values;
}
}
$table_num++;
}
$combined = array_merge_recursive($x01, $crk);
// after arrays are merged, remove duplicate values
foreach ($combined as $name => $value) {
if ($value['name']) {
$combined[$name]['name'] = $name;
}
if ($value['team']) {
$combined[$name]['team'] = $value['team'][0];
}
}
echo json_encode($combined, JSON_PRETTY_PRINT);
I am Trying to fill my Excel sheet with the data i filtered through the methods i have made. For now i am getting a sheet but i only have only one row filled not the other it's not getting the data i provide it though my object
I am trying my sheet something similar to this sheet .
i am trying to write code in this part of code :
public function export($Sets,$disp_filter)
{
$objPHPExcel = new PHPExcel();
$objPHPExcel->getProperties()->setTitle("Offic excel Test Document");
$styleArray = array(
'font' => array(
'bold' => true,
'color' => array('rgb' => 'FF0000'),
'size' => 10,
'name' => 'Verdana'
));
$objPHPExcel->getActiveSheet()->getStyle('A1')->applyFromArray($styleArray);
$excel_out = array($this->outputSampleName($Sets));
// var_dump($excel_out);
// exit;
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Sample Size and Margin of Error');
$rowCount = 2;
foreach ($excel_out as $key=> $line)
{
$colCount = 'A';
$i=0;
// $line = array($Set['name']);
// $CT = $Set['crossTabs']['base'];
// $Moe = array($CT['sample']['moe']);
foreach($line as $col_value)
{
// var_dump($col_value);
// exit;
$objPHPExcel->getActiveSheet()->setCellValue($colCount.$rowCount, $col_value[$i])
->getStyle($colCount.$rowCount)->applyFromArray($styleArray);
$colCount++;
}
$rowCount++;
$i++;
}
return $objPHPExcel;
}
protected function outputSampleName($Sets)
{
foreach ($Sets as $Set)
{
$CT = $Set['crossTabs']['base'];
$line = array(
$Set['name'],
$CT['sample']['moe'] . '%'
);
$excel_out []= $line;
}
return $excel_out;
}
when i see by var_dump($excel_out)
i have this data structure :
**Please suggest me something how can i get those percentage values in my next row in optimized way.
for now i can only loop through the sample[name] which are (enthusiasts, hunter, new shooters etc. )from that array. **
thanks in advance
this code get table.
I want to remove first and second tr tag in the table.
$data = array();
$table_rows = $xpath->query('//table[#class="adminlist"]/tr');
if($table_rows->length <= 0) { // exit if not found
echo 'no table rows found';
exit;
}
foreach($table_rows as $tr) { // foreach row
$row = $tr->childNodes;
if($row->item(0)->tagName != 'tblhead') { // avoid headers
$data[] = array(
'Name' =>trim($row->item(0)->nodeValue),
'LivePrice' => trim($row->item(2)->nodeValue),
'Change'=> trim($row->item(4)->nodeValue),
'Lowest'=> trim($row->item(6)->nodeValue),
'Topest'=> trim($row->item(8)->nodeValue),
'Time'=> trim($row->item(10)->nodeValue),
);
}
}
and question 2
In the bellow table tr have two class --- EvenRow_Print and OddRow_Print ---
$data = array();
$table_rows = $xpath->query('//table/tr');
if($table_rows->length <= 0) {
echo 'no table rows found';
exit;
}
foreach($table_rows as $tr) { // foreach row
$row = $tr->childNodes;
if($row->item(0)->tagName != 'tblhead') { // avoid headers
$data[] = array(
'Name' =>trim($row->item(0)->nodeValue),
'LivePrice' => trim($row->item(2)->nodeValue),
'Change'=> trim($row->item(4)->nodeValue),
'Lowest'=> trim($row->item(6)->nodeValue),
'Topest'=> trim($row->item(8)->nodeValue),
'Time'=> trim($row->item(10)->nodeValue),
);
}
}
How can I echo both tr in one 2d array .
examp.
Array(
[0] => Array(
//array
)
}
Thank's
For question 1 - there are different ways to skip the first and last element, e.g. removing the first entry using array_shift() and the last entry using array_pop(). But as it's not clear if it'd be better to keep the array as it is, it's possible to skip both entries in the foreach in an easy way like using a counter, continuing for the first entry and breaking for the last:
$i = 0;
$trlength = count($table_rows);
foreach( ...) {
if ($i == 0) // is true for the first entry
{
$i++; // increment counter
continue; // continue with next entry
}
else if ($i == $trlength - 1) // last entry, -1 because $i starts from 0
{
break; // exit foreach loop
}
.... // handle all other entries
$i++; // increment counter in foreach loop
}
I have a text file (which essentially is a csv without the extension) that has 150,000 lines in it. I need to remove duplicates by key then insert them into the database. I'm attempting fgetcvs to read it line by line, but I don't want to do 150,000 queries. So this is what I came up with so far: (keep in mind i'm using laravel)
$count = 0;
$insert = [];
if (($handle = fopen("myHUGEfile.txt", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$count++;
//See if this is the top row, which in this case are column headers
if ($count == 1) continue;
//Get the parts needed for the new part
$quantity = $data[0];
$part_number = $data[1];
$manufacturer = $data[2];
$new_part = [
'manufacturer' => $manufacturer,
'part_number' => $part_number,
'stock' => $quantity,
'price' => '[]',
'approved' => 0,
];
$insert[] = $new_part;
}
fclose($handle);
} else {
throw new Exception('Could not open file for reading.');
}
//Remove duplicates
$newRows = [];
$parsedCount = 0;
foreach ($insert as $row) {
$x = 0;
foreach ($newRows as $n) {
if (strtoupper($row['part_number']) === strtoupper($n['part_number'])) {
$x++;
}
}
if ($x == 0) {
$parsedCount++;
$newRows[] = $row;
}
}
$parsed_rows = array_chunk($newRows, 1000, true);
$x = 0;
foreach ($parsed_rows as $chunk) {
//Insert
if (count($chunk) > 0)
if (DB::table('search_parts')->insert($chunk))
$x++;
}
echo $x . " chunks inserted.<br/>" . $count . " parts started with<br/>" . $parsedCount . " rows after duplicates removed.";
But it's very clunky, I have only tested it with a little over 1000 rows and it works using localhost. But i'm afraid if I push it up to production it won't be able to handle all 150,000 rows. The file is about 4mb.
Can someone show me a better more efficient way to do this?
Right now, you're keeping the first duplicate record. If you're ok keeping the last dupe, you can just change
$insert[] = $new_part;
to
$insert[strtoupper($part_number)] = $new_part
That way, your $insert array will only have one value for each $part_number. Your inserts will be a little slower, but you can drop all of the code which checks for duplicates which looks very, very slow.
4Mb is not remotely a "huge" file. I'd just read the whole thing into an assoc array keyed by part number, which will inherently de-dupe, giving you the last row whenever a duplicate is encountered. Something like this maybe:
$parts = [];
foreach (explode("\n", file_get_contents('file')) as $line) {
$part = str_getcsv($line);
$parts[$part[1]] = [
'manufacturer' => $part[2],
'part_number' => $part[1],
'stock' => $part[0],
'price' => '[]',
'approved' => 0,
];
}
// $parts now contains unique part list
foreach ($parts as $part) {
$db->insert($part);
}
If you don't want duplicates on a certain or multiple keys, you can make it easy on yourself and just add a UNIQUE INDEX on the key you don't want duplicates for on the table.
This way, all you have to worry about is processing the file. When it reaches a duplicate key, it will not be able to insert it and will continue.
It would also make it easier in the future because you wouldn't have to modify your code if you need to do checks on additional columns. Just modify the index.
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
// I wish
echo $cellIterator->getCell("A3"); // row: $row, cell: A3
}
}
I'm looking for a similar method which named getCell above or well-writed PHPExcel documentation.
Thanks.
If you have the $row information from RowIterator, you can just easily call:
$rowIndex = $row->getRowIndex ();
$cell = $sheet->getCell('A' . $rowIndex);
echo $cell->getCalculatedValue();
The complete code would be:
foreach($worksheet->getRowIterator() as $row){
$rowIndex = $row->getRowIndex();
$cell = $worksheet->getCell('A' . $rowIndex);
echo $cell->getCalculatedValue();
$cell = $worksheet->getCell('B' . $rowIndex);
echo $cell->getCalculatedValue();
}
This is what I needed:
function coordinates($x,$y){
return PHPExcel_Cell::stringFromColumnIndex($x).$y;
}
implementation:
coordinates(5,7); //returns "E7"
Though one could also do this for A-Z columns:
function toNumber($dest)
{
if ($dest)
return ord(strtolower($dest)) - 96;
else
return 0;
}
function lCoordinates($x,$y){
$x = $toNumber($x);
return PHPExcel_Cell::stringFromColumnIndex($x).$y;
}
implementation:
lCoordinates('E',7); //returns "E7"
Rather than iterate all the Cells in a row, when not use the rangeToArray() method for the row, and then use array_intersect_key() method to filter only the columns that you want:
$worksheet = $objPHPExcel->getActiveSheet();
$highestColumn = $worksheet->getHighestColumn();
$columns = array_flip(array('A','C','E'));
foreach($worksheet->getRowIterator() as $row)
{
$range = 'A'.$row->getRowIndex().':'.$highestColumn.$row->getRowIndex();
$rowData = $worksheet->rangeToArray( $range,
NULL,
TRUE,
TRUE,
TRUE);
$rowData = array_intersect_key($rowData[$row->getRowIndex()],$columns);
// do what you want with the row data
}
EDIT
The latest SVN code introduces a number of new methods to th iterators, including the ability to work with ranges, or set the pointer to specific rows and columns