kiner_shah
kiner_shah

Reputation: 4681

Problems in generating proper XML file using PHP

I am trying to generate / update an XML file dynamically using PHP. The following is the structure of the XML file I want:

test1.xml

<?xml version="1.0" encoding="UTF-8"?>
<month month_no="2">
  <dailytotal date="2018-02-28">10</dailytotal>
  <monthlytotal>10</monthlytotal>
</month>

The dailytotal element stores the total value for each day (which is indicated by date attribute) and the monthlytotal element stores the total value for each month (sum of dailytotals). The month is indicated by month_no attribute.

The problem I am facing is when I generate XML file on a date which is belonging to a different month (say month_no="3"), the file is overwritten and all its previous contents are gone.

I tried searching for any possible problems (for e.g. in handling the DOM tree of the XML document) but I couldn't find any and my code logic seems correct!

Also, when I run the same script again, I get a warning message which I couldn't understand why I get it.

Warning: DOMDocument::load(): Extra content at the end of the document in file:/C:/xampp/htdocs/DailyExpenseCalculator/test1.xml, line: 6 in C:\xampp\htdocs\DailyExpenseCalculator\xml_modify.php on line 8

I thought the warning was due to an additional newline in the file, but removing it doesn't work.

xml_generator.php

<?php
    // Loading the XML file and updating data to it
    $date = date('Y-m-d');
    $balanceObj = 10;
    $doc = new DOMDocument("1.0", "UTF-8");

    $doc->preserveWhiteSpace = false;
    $doc->formatOutput = true;

    $doc->load('test1.xml');

    $months = $doc->getElementsByTagName('month');

    $cur_month = (int) date('m');
    $cur_date = $date;

    $found_month = false;
    //echo "<p>Current date: ".$cur_date."</p>";
    //echo "<p>Current month: ".$cur_month."</p>";

    foreach($months as $month) {
        $month_no = (int) $month->getAttribute('month_no');

        if($cur_month == $month_no) {
            //echo "<p>Found month</p>";
            $dailytotals = $month->getElementsByTagName('dailytotal');
            $found_date = false;

            foreach($dailytotals as $d) {
                $this_date = $d->getAttribute('date');

                if($this_date === $cur_date) {
                    // echo "<p>Found date</p>";
                    $new_dailytotal = $doc->createElement('dailytotal', (float) $balanceObj);
                    $new_dailytotal->setAttribute('date', $date);
                    $d->parentNode->replaceChild($new_dailytotal, $d);  // (new node, old node)
                    $found_date = true;
                    break;
                }
            }

            if($found_date == false) {  // entry on a new day
                //echo "<p>Didn't found date</p>";
                $newDailyTotal = $doc->createElement('dailytotal', (float) $balanceObj);
                $newDailyTotal->setAttribute('date', $date);
                $m = $month->getElementsByTagName('monthlytotal')->item(0);
                $newBalance = ((float) $m->nodeValue) + ((float) $balanceObj);
                $newMonthlyTotal = $doc->createElement('monthlytotal', (float) $newBalance);
                $m->parentNode->replaceChild($newMonthlyTotal, $m);
                $newDailyTotal = $month->appendChild($newDailyTotal);
            }

            else {                      // entry on the same day
                $m = $month->getElementsByTagName('monthlytotal')->item(0);
                // $oldBalance = (float) $m->nodeValue;
                // $newBalance = $oldBalance - $oldDailyTotal + $balanceObj;
                $newBalance = ((float) $m->nodeValue) + ((float) $balanceObj);
                $newMonthlyTotal = $doc->createElement('monthlytotal', (float) $newBalance);
                $m->parentNode->replaceChild($newMonthlyTotal, $m);
            }

            $found_month = true;
            break;
        }
    }

    if($found_month == false) {
        // echo "<p>Didn't found month</p>";
        $newMonthElement = $doc->createElement('month');
        $newMonthElement->setAttribute('month_no', $cur_month);
        $newDailyTotalElement = $doc->createElement('dailytotal', (float) $balanceObj);
        $newDailyTotalElement->setAttribute('date', $date);
        $newMonthlyTotalElement = $doc->createElement('monthlytotal', (float) $balanceObj);
        $newDailyTotalElement = $newMonthElement->appendChild($newDailyTotalElement);
        $newMonthlyTotalElement = $newMonthElement->appendChild($newMonthlyTotalElement);
        $newMonthElement = $doc->appendChild($newMonthElement);
    }

    $doc->save('test1.xml');
?>

Upvotes: 2

Views: 273

Answers (1)

Syscall
Syscall

Reputation: 19764

You need a root node to put your <month> tags.

First, change your initial XML :

<?xml version="1.0" encoding="UTF-8"?>
<months>
    <month month_no="2">
        <dailytotal date="2018-02-28">10</dailytotal>
        <monthlytotal>10</monthlytotal>
    </month>
</months>

Then, after loading your XML :

$months_tags = $doc->getElementsByTagName('months');
$months_tag = $months_tags[0];

Finally, put your month tag into the root node :

$months_tag->appendChild($newMonthElement);

Full code : (check /// <<< CHANGE)

// Loading the XML file and updating data to it
$date = date('Y-m-d');
$balanceObj = 10;
$doc = new DOMDocument("1.0", "UTF-8");

$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;

$doc->load('test1.xml');

$months_tags = $doc->getElementsByTagName('months'); /// <<< CHANGE
$months_tag = $months_tags[0]; /// <<< CHANGE

$months = $doc->getElementsByTagName('month');

$cur_month = (int) date('m');
$cur_date = $date;

$found_month = false;
echo "<p>Current date: ".$cur_date."</p>";
echo "<p>Current month: ".$cur_month."</p>";

foreach($months as $month) {
    $month_no = (int) $month->getAttribute('month_no');

    if($cur_month == $month_no) {
        echo "<p>Found month</p>";
        $dailytotals = $month->getElementsByTagName('dailytotal');
        $found_date = false;

        foreach($dailytotals as $d) {
            $this_date = $d->getAttribute('date');

            if($this_date === $cur_date) {
               echo "<p>Found date</p>";
                $new_dailytotal = $doc->createElement('dailytotal', (float) $balanceObj);
                $new_dailytotal->setAttribute('date', $date);
                $d->parentNode->replaceChild($new_dailytotal, $d);  // (new node, old node)
                $found_date = true;
                break;
            }
        }

        if($found_date == false) {  // entry on a new day
            echo "<p>Didn't found date</p>";
            $newDailyTotal = $doc->createElement('dailytotal', (float) $balanceObj);
            $newDailyTotal->setAttribute('date', $date);
            $m = $month->getElementsByTagName('monthlytotal')->item(0);
            $newBalance = ((float) $m->nodeValue) + ((float) $balanceObj);
            $newMonthlyTotal = $doc->createElement('monthlytotal', (float) $newBalance);
            $m->parentNode->replaceChild($newMonthlyTotal, $m);
            $newDailyTotal = $month->appendChild($newDailyTotal);
        }

        else {                      // entry on the same day
            $m = $month->getElementsByTagName('monthlytotal')->item(0);
            // $oldBalance = (float) $m->nodeValue;
            // $newBalance = $oldBalance - $oldDailyTotal + $balanceObj;
            $newBalance = ((float) $m->nodeValue) + ((float) $balanceObj);
            $newMonthlyTotal = $doc->createElement('monthlytotal', (float) $newBalance);
            $m->parentNode->replaceChild($newMonthlyTotal, $m);
        }

        $found_month = true;
        break;
    }
}

if($found_month == false) {

    echo "<p>Didn't found month</p>";
    $newMonthElement = $doc->createElement('month');
    $newMonthElement->setAttribute('month_no', $cur_month);
    $newDailyTotalElement = $doc->createElement('dailytotal', 2);
    $newDailyTotalElement->setAttribute('date', $date);
    $newMonthlyTotalElement = $doc->createElement('monthlytotal', 3);
    $newDailyTotalElement = $newMonthElement->appendChild($newDailyTotalElement);
    $newMonthlyTotalElement = $newMonthElement->appendChild($newMonthlyTotalElement);
    $months_tag->appendChild($newMonthElement); /// <<< CHANGE
}

$doc->save('test1.xml');

Upvotes: 2

Related Questions