PHP + XPath + fputcsv - Storing data in arrays - php

I'm parsing some HTML with DOM/Xpath, with the ultimate goal of generating a .CSV file with the data I've grabbed with my queries.
The current code below works, but only returns the last product name. I know I'm sort of on the right track here, but I'm maxed out and cannot figure this out. Any help would be greatly, greatly appreciated. Thanks.
$names = array();
$result = $xpath->query("//div[#class='product-name']");
foreach ($result as $nam) {
$names[] = $nam->nodeValue;
$i = 0;
$values=$names[$i] = $nam->nodeValue;
}
$list = array (
array('Product Name','Stock Level','Price'),
array($values, '456', '789'),
);
$fp = fopen('product-sheet.csv', 'w');
foreach ($list as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);

I'm not entirely sure what you're trying to achieve but hopefully this will get you nearer to your goal.
<?php
//mocked up input, substitute for your HTML source
$input = "<html>
<div class='product-name'>test1</div>
<div class='product-name'>test2</div>
<div class='product-name'>test3</div>
<div class='product-name'>test4</div>
<div class='product-name'>test5</div>
</html>";
$doc = new DOMDocument();
#$doc->loadHTML($input);
libxml_use_internal_errors(FALSE);
$xpath = new DomXPath($doc);
$list = array (
array('Product Name','Stock Level','Price')
);
$result = $xpath->query("//div[#class='product-name']");
foreach ($result as $nam) {
$value = $nam->nodeValue;
$list[] = array($value, '456', '789'); //Appends an array to the lists array
}
$fp = fopen('product-sheet.csv', 'w');
foreach ($list as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
?>

The problem is you're setting $i inside your loop.
foreach ($result as $nam) {
$names[] = $nam->nodeValue;
$i = 0;
$values=$names[$i] = $nam->nodeValue;
}
On each iteration, $i is being reset to 0. Try something like this instead:
for($i=0; $i< count($result); $i++) {
$names[] = $result->nodeValue;
$values=$names[$i] = $result->nodeValue;
}

Related

PHP script to create new csv from another csv after rearranging the data

I have a csv with following structure:
And I need the output csv as follows:
That means taking the faetures from each column and put it in the single row.
I am using php office to fetch and write the csv. I have written the following:
if ( false === $handle = fopen('../../../3b.csv', 'r') )
throw new Exception('File open failed.');
$headers = fgetcsv($handle);
$row = '';
$row = array();
$data = '';
$data = array();
while ( false !== $fields = fgetcsv($handle) ) {
$fields = array_combine($headers, $fields);
foreach($fields as $key=>$value){
if($key!='sku'){
if($value==''){
continue;
}
}
$row[$key] = $value;
}
if(sizeof($row)==1){
unset($row['sku']);
}
$row = array_filter( $row );
$data[] = $row;
}
$data = array_filter($data);
$use_keys = ['sku','AC Rating','color','Feature','Finish','Grade','Installation Location','Installation Method','Plank Style','Size','Specie','Tile Format','Warranty','Wear Layer','Width','LifeStyle',
'Material','Style','Thickness','Appearance','PEIRating','ProtectionRating'];
foreach($data as $key=>$value){
$new_arr = [];
foreach($use_keys as $apk_item) {
$new_value = '';
if (isset($data[$key][$apk_item])) {
$new_value = str_replace(",","|",$data[$key][$apk_item]);
}
$new_arr[$apk_item] = $new_value;
}
$data[$key] = $new_arr;
}
$data = array_filter($data, 'array_filter');
$final_array = array();
foreach ($data as $features) {
$product = array('feature' => '');
foreach ($features as $key => $feature) {
if ($key == 'sku') {
$product['sku'] = $feature;
}
else {
if($feature!=''){
$product['feature'] .= $key;
$product['value'] .= $feature;
}
}
}
$final_array[] = $product;
}
$final_array = array_filter($final_array);
$table = '<table border="1" id="csvtable">
<thead><tr><th>sku</th><th>feature</th><th>value</th></tr></thead>
<tbody>';
foreach($final_array as $value){
$sku = $value["sku"];
$combinedfeature = explode(",", $value['feature']);
foreach($combinedfeature as $single){
$table .= '<tr><td width="20%">'.$sku.'</td><td width="40%">'.$single['feature'].'</td><td width="40%">'.$single['value'].'</td></tr>';
}
}
$table .= '</tbody></table>';
print_r($table);
It's giving wrong output. How can I do this? Anyone can help, please?
A much more compact method would be to read the input and write out the target file in one loop.
This code reads in each line, combines it with the header and then extracts the sku (and removes it from the details). Then loops over the remaining details, and if there is a value to output it writes the output to the result file.
As each value may also be a comma separated list, this uses explode() to split them into individual items and writes them out as separate parts...
$inputFile = "a.csv";
$outputFile = "a1.csv";
$inputHandle = fopen($inputFile, 'r');
$outputHandle = fopen($outputFile, 'w');
$headers = fgetcsv($inputHandle);
fputcsv($outputHandle, ["sku", "feature", "value" ]);
while ( false !== $fields = fgetcsv($inputHandle) ) {
$fields = array_combine($headers, $fields);
$sku = $fields['sku'];
unset($fields['sku']);
foreach ( $fields as $name => $field ) {
if (!empty(trim($field))) {
$subFields = explode(",", $field );
foreach ( $subFields as $value ) {
fputcsv($outputHandle, [$sku, $name, $value]);
}
}
}
}
fclose($inputHandle);
fclose($outputHandle);

PHP Get duplicate values in array and average second value

I have an array that looks like this:
$ratingsInPosts = array
(
array("1",3),
array("2",5),
array("2",2),
array("5",2),
array("90",1),
array("5",6),
array("2",2),
);
I Want to find duplicate values in the first column and avarage its values from the second column.
So that this("1",3),("2",5),("2",2),("5",2),("90",1),("5",6),("2",2)
ends up like this ("1",3),("2",3),("5",4),("90",1)
Try this tested solution
I got the required Output
$ratingsInPosts = array
(
array("1",3),
array("2",5),
array("2",2),
array("5",2),
array("90",1),
array("5",6),
array("2",2),
);
$arr1 = array_column($ratingsInPosts, 0);
$p = array_count_values($arr1);
foreach($p as $key => $value)
{
$sum = 0;
for($i=0; $i < $value; $i++)
{
$pos = array_search($key, $arr1);
$sum += $ratingsInPosts[$pos][1];
unset($arr1[$pos]);
unset($ratingsInPosts[$pos]);
}
$re[] = array('"'.$key.'"',$sum/$value);
}
print_r($re);
I hope it helps you:
$groups = array();
// in this loop we group values by first column
foreach ($ratingsInPosts as $row) {
$key = $row[0];
if (!isset($groups[$key]) {
$groups[$key] = array();
}
$groups[$key][] = $row[1];
}
$result = array();
foreach ($groups as $key => $value) {
$avg = array_sum($value) / count($value);
$row = array($key, $avg);
$result[] = $row;
}
<?php
header('Content-Type: text/plain');
$ratingsInPosts = array(array("1",3),array("2",5),array("2",2),array("5",2),array("90",1),array("5",6),array("2",2));
$result = array();
$output = array();
foreach($ratingsInPosts as $array){
$result[$array[0]][] = $array[1];
}
foreach($result as $key=>$array){
$output[] = array($key,round(array_sum($array)/count($array)));
}
var_export($output);
?>

PHPExcel -> creating duplicate worksheets

I am trying to create a application that will parse a CSV file of items, and do specific things for each item in the CSV file. I have the upload/parsing figured out, however, when I export it to Excel each CSV entry is duplicated in the worksheets. For example, if there were 4 entries in the CSV file, the first entry is duplicated 4 times, the second entry is duplicated 3 times, etc. I have look through documentation for days, and I am unable to locate where I am going wrong. Below is the code that is generating the XLSX file.
if (in_array($type,$csv_types)){
if (move_uploaded_file($tmp_name, $path)){
foreach ($csv as $locar){
foreach ($locar as $locid){
$locs[] = $locid;
$count = count($locs);
/*if ($i < $count - 1){
$objPHPExcel->createSheet();
$i++;
}*/
$xmls = array();
foreach ($locs as $locids){
$url = 'Link to XML API' . $locids;
$xmls[] = $url;
$objWorkSheet = $objPHPExcel->createSheet();
$objWorkSheet->setTitle($locids);
$objPHPExcel->setActiveSheetIndexByName($locids);
}
foreach ($xmls as $links){
$locations = explode("=", $links);
$row = 1;
//
$objPHPExcel->getActiveSheet()->setCellValue('A'.$row,'Location ID:' . $locations[1]);
$row++;
$objPHPExcel->getActiveSheet()->SetCellValue('A'.$row,'Database');
$objPHPExcel->getActiveSheet()->SetCellValue('B'.$row,'URL');
$row++;
$xml = simplexml_load_file($links);
foreach ($xml as $product){
foreach ($product->title as $item){
$dbtitle = str_replace(',',' ',$item);
$dblink = $product->link;
}
$objPHPExcel->setActiveSheetIndexByName($locations[1]);
$objPHPExcel->getActiveSheet()->SetCellValue('A'.$row,$dbtitle);
$objPHPExcel->getActiveSheet()->SetCellValue('B'.$row,$dblink);
$row++;
}
}
}
}
}
The Links that are generated by the code are only showing up in the correct worksheet (the first created worksheet for the entry in the csv). Any help would be greatly appreciated.
Try this...
if (in_array($type,$csv_types)){
if (move_uploaded_file($tmp_name, $path)){
foreach ($csv as $key => $locar){
$locs[] = $locid[$key];
$count = count($locs);
/*if ($i < $count - 1){
$objPHPExcel->createSheet();
$i++;
}*/
$xmls = array();
$url = 'Link to XML API' . $locids[$key];
$xmls[] = $url;
$objWorkSheet = $objPHPExcel->createSheet();
$objWorkSheet->setTitle($locids[$key]);
$objPHPExcel->setActiveSheetIndexByName($locids[$key]);
$locations = explode("=", $links[$key]);
$row = 1;
//
$objPHPExcel->getActiveSheet()->setCellValue('A'.$row,'Location ID:' . $locations[1]);
$row++;
$objPHPExcel->getActiveSheet()->SetCellValue('A'.$row,'Database');
$objPHPExcel->getActiveSheet()->SetCellValue('B'.$row,'URL');
$row++;
$xml = simplexml_load_file($links[$key]);
foreach ($xml as $product){
foreach ($product->title as $item){
$dbtitle = str_replace(',',' ',$item);
$dblink = $product->link;
}
$objPHPExcel->setActiveSheetIndexByName($locations[1]);
$objPHPExcel->getActiveSheet()->SetCellValue('A'.$row,$dbtitle);
$objPHPExcel->getActiveSheet()->SetCellValue('B'.$row,$dblink);
$row++;
}
}
}
}
Also can you post the $xml array (print_r)...
$xml = simplexml_load_file($links[$key]);

Merge and transpose 3 arrays of data [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
foreach with three variables add
(4 answers)
Closed 6 months ago.
There are three single dimensional arrays that needs to be saved in csv
$arr1=array(1,2,3);
$arr2=array('a','b','c');
$arr3=array('x','y','z');
I need to save the above arrays in the csv like the following example-
1,a,x
2,b,y
3,c,z
I have tried the following code but its not saving in that format
$handle = fopen('file.csv', 'w');
$data=array($arr1,$arr2,$arr3);
foreach ($data as $line) {
fputcsv($handle, $line);
}
fclose($handle);
Output
1,2,3
a,b,c
x,y,z
Transpose the data before writing to the CSV
$data = array($arr1,$arr2,$arr3);
$transposedData = call_user_func_array(
'array_map',
array_merge(
array(NULL),
$data
)
);
$handle = fopen('file.csv', 'w');
foreach ($transposedData as $line) {
fputcsv($handle, $line);
}
fclose($handle);
foreach ($arr1 as $key => $value) {
fputcsv($handle, array($value, $arr2[$key], $arr3[$key]));
}
try like below:-
$arr1=array(1,2,3);
$arr2=array('a','b','c');
$arr3=array('x','y','z');
$handle = fopen('file.csv', 'w');
for($i=0; $i<count($arr1); $i++) {
$data=array($arr1[$i],$arr2[$i],$arr3[$i]);
fputcsv($handle, $data);
}
fclose($handle);
output
1 a x
2 b y
3 c z
Try this,Just take the transpose of the array before fputcsv
<?php
$arr1=array(1,2,3);
$arr2=array('a','b','c');
$arr3=array('x','y','z');
$data=array($arr1,$arr2,$arr3);
$rows = count($data);
$cols = count($data[0]);
$ridx = 0;
$cidx = 0;
$out = array();
foreach($data as $rowidx => $row){
foreach($row as $colidx => $val){
$out[$ridx][$cidx] = $val;
$ridx++;
if($ridx >= $rows){
$cidx++;
$ridx = 0;
}
}
}
$handle = fopen('file.csv', 'w');
foreach ($out as $line) {
fputcsv($handle, $line);
}
fclose($handle);
?>
Output
1,a,x
2,b,y
3,c,z
<?php
$arr1=array(1,2,3);
$arr2=array('a','b','c');
$arr3=array('x','y','z');
$output = '';
$data=array($arr1,$arr2,$arr3);
$size=count($data[0]);
//all arrays must have the same size! and $data must contain at least one item
for ($i = 0; $i < $size; $i++) {
foreach ($data as $arr) {
$output .= $arr[$i] . ';';
}
$output .= "\n";
}
file_put_contents($output);
?>
Expected output:
1;a;x;
2;b;y;
3;c;z;

echoing foreach loop

i have the following code
$contents = file_get_contents('folder/itemtitle.txt');
$fnamedata = file_get_contents('folder/fname.txt');
$fnamearray = explode("\n", $fnamedata);
$contents = explode("\n", $contents);
foreach ($contents as $key => $itemline)
{
}
foreach ($fnamearray as $key2 => $fname)
{
echo ($fname);
echo ($itemline);
}
what i want to do is to have the first line of each file echo so the output looks like
fname[0},itemline[0],fname[1],itemline[1]
what i am getting with the following is just this
fname[0],fname[1],fname[2].... ect
h
Assuming the indexes will always match:
$contents = file_get_contents('folder/itemtitle.txt');
$fnamedata = file_get_contents('/home/b1396hos/public_html/ofwgkta.co.uk/dd_folder/fname.txt');
$fnamearray = explode("\n", $fnamedata);
$contents = explode("\n", $contents);
for($i = 0; $i < count($contents); $i++)
{
echo $fnamearray[$i];
echo $contents[$i];
}
Since both arrays are simple, consecutive numeric indexed arrays, you can just use a for loop:
$l = max(count($fnamedata),count($contents));
for($i=0; $i<$l; $i++) {
$itemline = $contents[$i];
$fname = $fnamearray[$i];
// do stuff
}

Categories