phpxmlcsvfgetsxmlwriter

PHP script writes the subset but when adding attributes to the root, it crashes


I have made this php script to convert CSV files into XML files. I have a for each loop that handles the records and the contents within this section. Which produces the following results.

current results

I have been adding the same loop to contain details within the root station to contain the results as pictured

desired results

But when I add this same loop to read the root it seems to break, as seems to crash. Even while trail and error, starting with just this section within the code and removing the but to no avail.

Also within in this some entries (data-481.xml) are empty but within the google drive have lines within the information for the data-481.csv.

Blank XML - data-481.csv https://drive.google.com/file/d/1pEinOeosPQQRoeQoJHfEb6L_80iD5bqr/view?usp=share_link

<?php

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

// List of CSV files
$csvFiles = [
    'data-203.csv',
    'data-206.csv',
    '.....'

];

// Loop through each CSV file
foreach ($csvFiles as $csvFile) {
    $csvFilePath = __DIR__ . '/' . $csvFile;
    
    // Open the CSV file
    if (($handle = fopen($csvFilePath, 'r')) !== false) {
        // Create an XMLWriter instance
        $xmlWriter = new XMLWriter();
        $xmlWriter->openURI(csvFileToXmlFile($csvFile));
        $xmlWriter->startDocument('1.0', 'UTF-8');
        $xmlWriter->startElement('Station');

        // Read the CSV file line by line
        while (($data = fgetcsv($handle,10000,';')) !== false) {
            // Skip empty lines
            if (count($data) === 0) {
                continue;
            }

            // Ensure the array has the necessary indexes
            if (count($data) >= 4) {
                // Extract the necessary data
                $timestamp = $data[0];
                $nox = $data[1];
                $no2 = $data[2];
                $no = $data[3];

                // Check if the attribute has a value
                if (trim($no) !== '') {
                    // Start XML record element
                    $xmlWriter->startElement('rec');
                    $xmlWriter->writeAttribute('ts', $timestamp);
                    $xmlWriter->writeAttribute('nox', $nox);
                    $xmlWriter->writeAttribute('no2', $no2);
                    $xmlWriter->writeAttribute('no', $no);
                    // End XML record element
                    $xmlWriter->endElement();
                }
            }
        }

        // Close XML elements and file
        $xmlWriter->endElement();
        $xmlWriter->endDocument();
        $xmlWriter->flush();
        fclose($handle);

        // Output success message
        $xmlFile = csvFileToXmlFile($csvFile);
        echo "XML file generated successfully: $xmlFile\n";
    }
}

// Function to convert CSV file name to XML file name
function csvFileToXmlFile($csvFile) {
    $fileParts = pathinfo($csvFile);
    $xmlFile = $fileParts['filename'] . '.xml';
    return $xmlFile;
}

?>

I am hoping to have all the files transfer into XML from the CSV with the desired <station element to hold <station id="481 location="Bath Road" geocode="51.3453, -2.55434">


Solution

  • Some changes made, first to ensure a valid XML file, and secondly to pull the right data from the right place

    // Loop through each CSV file
    foreach ($csvFiles as $csvFile) {
        $csvFilePath = __DIR__ . '/' . $csvFile;
        
        // Open the CSV file
        if (($handle = fopen($csvFilePath, 'r')) !== false) {
            // Create an XMLWriter instance
    
            /* You cant write the Station element until you have read the csv file
                as it needs data for its properties from there
                So moved inside the while loop
            */
    
            $xmlWriter = new XMLWriter();
            $xmlWriter->openURI(csvFileToXmlFile($csvFile));
            $xmlWriter->startDocument('1.0', 'UTF-8');
    
            $flagFirstLineWritten = false;      // control writing on Station element only once
            
            while (($data = fgetcsv($handle,10000,';')) !== false) {
                // Skip empty lines
                if (count($data) === 0) {
                    continue;
                }
                /*
                    output the Station element with its properties only once
                */
                if ( ! $flagFirstLineWritten ) {
                    $xmlWriter->startElement('Station');
                    $xmlWriter->writeAttribute('id',        $data[4]);
                    $xmlWriter->writeAttribute('name',      $data[17]);
                    $xmlWriter->writeAttribute('geocode',   $data[18]);
                    $xmlWriter->endAttribute();
                    $flagFirstLineWritten = true;
                }
                
                // Ensure the array has the necessary indexes
                if (count($data) >= 4) {
                    // Extract the necessary data
                    /*
                        convert the DATE to a timestamp
                    */
                    $ts = (new DateTime())->createFromFormat( DateTimeInterface::ISO8601, $data[0]);
                                    
                    // Check if the attribute has a value
                    if (trim($data[3]) !== '') {
                        // Start XML record element
                        $xmlWriter->startElement('rec');
                        $xmlWriter->writeAttribute('ts',    (string)$ts->getTimestamp());
                        $xmlWriter->writeAttribute('nox',   $data[1]);
                        $xmlWriter->writeAttribute('no',    $data[2]);
                        $xmlWriter->writeAttribute('no2',   $data[3]);
                        // End XML record element
                        $xmlWriter->endElement(); // end rec
                    }
                }
            }
    
            $xmlWriter->endElement();   // station element
            $xmlWriter->endDocument();
            $xmlWriter->flush();
            fclose($handle);
    
            // Output success message
            $xmlFile = csvFileToXmlFile($csvFile);
            echo "XML file generated successfully: $xmlFile\n";
        }
    }
    
    // Function to convert CSV file name to XML file name
    function csvFileToXmlFile($csvFile) {
        $fileParts = pathinfo($csvFile);
        $xmlFile = $fileParts['filename'] . '.xml';
        return $xmlFile;
    }
    

    RESULTS, example

    <?xml version="1.0" encoding="UTF-8"?>
    <Station id="203" name="Brislington Depot" geocode="51.441747180510106, -2.5599558321904605">
        <rec ts="1546326000" nox="18.5" no="12.5" no2="3.75"/>
        <rec ts="1546412400" nox="163.75" no="55.0" no2="71.0"/>
        
        . . .
    
        . . .
    </Station>