0

I am having trouble deleting a record from an XML file using PHP.

I keep getting the following error:

Fatal error: Cannot use object of type DOMElement as array in /Applications/XAMPP/xamppfiles/htdocs/catalogue/deleteaction.php on line 19

This is the code:

XML

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="catalogue_overview.xsl"?>

<catalogue>
  <record>
    <catId>001</catId>
    <title>Fungus</title>
    <location>GP</location>
    <photographer>jrm</photographer>
    <equipment>Canon EOS 40D</equipment>
    <caption>Small fungus</caption>
    <notes>This is a very rare species of fungus</notes>
    <date>10/8/2012</date>
    <imageUrl>images/IMG_1684.jpg</imageUrl>
  </record>
</catalogue>

PHP cataloguedelete.php

!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Photo Catalogue - Delete Entry</title>

<link rel="stylesheet" type="text/css" href="css/style.css"/>

</head>

<body>


    <h1>Delete Entry From Catalogue</h1>

    <p>DDDDDDD</p>

<?
echo "<form action='deleteaction.php' method='post'>\n";
$doc = new DOMDocument();
$doc->load('catalogue.xml');
$catdelete = $doc->getElementsByTagName("record");
foreach($catdelete as $record) {

  $catIds = $record->getElementsByTagName( "catId" );
  $catId = $catIds->item(0)->nodeValue;

  $titles = $record->getElementsByTagName( "title" );
  $title = $titles->item(0)->nodeValue;

  $locations = $record->getElementsByTagName( "location" );
  $location = $locations->item(0)->nodeValue;

  $photographers = $record->getElementsByTagName( "photographer" );
  $photographer = $photographers->item(0)->nodeValue;

  $equip = $record->getElementsByTagName( "equipment" );
  $equipment = $equip->item(0)->nodeValue;

  $captions = $record->getElementsByTagName( "caption" );
  $caption = $captions->item(0)->nodeValue;

  $note = $record->getElementsByTagName( "notes" );
  $notes = $note->item(0)->nodeValue;

  $dates = $record->getElementsByTagName( "date" );
  $date = $dates->item(0)->nodeValue;

  echo "<input type='checkbox' name='EntriesToRemove[]' value='" . $catId . "'> $title, &quot;$location&quot;<br>\n";
}
echo "<br><input type='submit' value='Delete Entry' />\n</form>\n";
?>

</body>
</html>

deleteaction.php

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
</head>

<body>

<?
$entries_to_remove = $_POST['EntriesToRemove'];


$doc = new DOMDocument();
$doc->load("catalogue.xml");

$catalogue = $doc->getElementsByTagName("catalogue");
foreach($catalogue as $record) {
    if($record['catId'] == $_POST["EntriesToRemove"]) {
        // unset($record);
        $catalogue->removeChild($record);
    }
}
$doc->save("catalogue.xml");
?>

</body>
</html>

The error is on the line:

if($record['catId'] == $_POST["EntriesToRemove"]) {

I am sure it is somehting simple I have missed

Any advice would be greatly appreciated

Many thanks

hakre
  • 193,403
  • 52
  • 435
  • 836
pelagos
  • 1,025
  • 3
  • 17
  • 27
  • It is very similar to this query but that did not help: http://stackoverflow.com/questions/19168009/php-delete-xml-tag-elements-based-on-selected-checkbox-array-values – pelagos Oct 23 '13 at 07:10

1 Answers1

1

You've setup EntriesToRemove to be an Array in the HTML - so you'll need to check if catId is an element of that array rather than equal to it (as suggested in the answer you linked). But also you need to properly grab the catId value from the DOMDocument (it's not an array) - you can actually use the code you use in the HTML to do that, something like this:

foreach($catalogue as $record) {
    // Get the CatIds from this record
    $catIds = $record->getElementsByTagName( "catId" );
    // get the first CatId (you might actually want to check this exists
    // first if you can't be sure the XML contains that key)
    $catId = $catIds->item(0)->nodeValue;
    // Look to see if the given catId is in the $_POST array
    if (in_array($catId, $_POST['EntriesToRemove'])) {
        // Found it!
    }
}

... should do the trick.

EDIT There was also an issue with the way we were looping through the <record> entries. And, because of the way the DOMDocument is modified when you do a removeChild you can't delete in the middle of a foreach loop (see comments here: DOMNode::removeChild). What you have to do instead is store a copy of the node you want to remove, then remove it outside of the loop.

So, what we end up with is:

$catalogue = $doc->getElementsByTagName("catalogue");
$records= $doc->getElementsByTagName('record');
$nodeToRemove= null;

foreach($records as $record) {
    // Get the CatIds from this record
    $catIds = $record->getElementsByTagName( "catId" );
    // get the first CatId (you might actually want to check this exists
    // first if you can't be sure the XML contains that key)
    $catId = $catIds->item(0)->nodeValue;
    // Look to see if the given catId is in the $_POST array
    if (in_array($catId, $_POST['EntriesToRemove'])) {
        // Found it! Store it for removal
        $nodeToRemove= $record;
    }
}

if ($nodeToRemove!=null) {
    $oldnode= $nodeToRemove->parentNode->removeChild($nodeToRemove);
}
$doc->save('catalogue.xml');
Clart Tent
  • 1,319
  • 2
  • 9
  • 11
  • As you can no doubt guess I am a novice. Thanks for the fast reply! I still seem to be getting the same error after substituting your code. I placed it in the deleteaction.php file and I get the same error. I then tried it in the cataloguedelete.php and I still get that error now it is in the form. Thanks for any advice. – pelagos Oct 23 '13 at 07:49
  • Sorry pelagos - my "fix" had an error in! I'd left in the $record['catId'] that we were supposed to replace. I've edited the answer above now. If you use that code to replace your `foreach` loop in `deleteaction.php` (and leave `cataloguedelete.php` as it was) you should be fine. Sorry - my fault! – Clart Tent Oct 23 '13 at 07:52
  • Thanks. That has fixed the error but it is not actually deleting the record from the xml file. I use Dreamweaver. When i open the 'cataloguedelete.php' and select the entry to delete - hit submit - I get a blank screen (where before i got the error). When I go back to Dreamweaver it says that the XML file has been changed (do i want to reload it - i say yes) but there are not actually any changes... Hope you can help! – pelagos Oct 23 '13 at 08:04
  • Sorry if this is a bit obvious, but did you put your `$catalogue->removeChild($record);` back into the foreach loop? (It's not in my sample code - it should be where the `// Found it!` comment is.) – Clart Tent Oct 23 '13 at 08:07
  • I had not - but I just did and it does the same thing. I also tried putting `unset($record);` there and it does the same thing. No error but no record deleted??? Thanks for your time... – pelagos Oct 23 '13 at 08:19
  • Right, let's hope for third time lucky! There is, apparently, an issue deleting within a foreach loop (as the DOMDocument gets re-built on the fly) - we also needed to grab the records as a collection to loop through. The code in my edit above should now work for you. – Clart Tent Oct 23 '13 at 08:59
  • You ROCK so hard right now! Thanks heaps... I will definitely learn from this exchange... – pelagos Oct 23 '13 at 09:04
  • You're welcome! Sorry it took so long to get to the right result! – Clart Tent Oct 23 '13 at 09:06
  • Hey danielpsc - thanks for your recent help - check out this other issue I am having trouble with (if you don't mind!) - http://stackoverflow.com/questions/19613601/update-rss-file-from-another-xml-file – pelagos Oct 27 '13 at 07:25