1

I have an xml file with many elements, I am looking to remove certain elements based on their indexes.

Sample XML:

<songs>
   <song>
      <title>A</title>
      <artist>AA</artist>
   </song>
</songs>

PHP Code I have so far:

<?php

$index = $_GET['song'];

$doc = new DOMDocument();
$doc->load("songs.xml");
$songs = $doc->getElementsByTagName("song");

foreach($songs as $song) {
    if(in_array($song[$index], $songs)){
        unset($song);
    }
}
$doc->save("songlist.xml");

?>

But I get this error from this code:

Fatal error: Cannot use object of type DOMElement as array

Any help at all is appreciated in this issue, thank you.

2
  • what are you trying to unset anyway? the whole <song>? Commented Jan 19, 2015 at 5:43
  • 1
    @Ghost yes, I am trying to remove the whole song child of songs. Commented Jan 19, 2015 at 5:52

3 Answers 3

1

If your intent is to remove the whole <song> element. Use ->removeChild():

$songs = $doc->getElementsByTagName('song');
$hated_artists = array('AA', 'BB', 'CC');
foreach($songs as $song) {
    $artist = $song->getElementsByTagName('artist')->item(0)->nodeValue;
    if(in_array($artist, $hated_artists)) { // if this song is sang by one of your hated artists
        $song->parentNode->removeChild($song); // remove this song
    }
}

Sample Usage

If you just want a simple criteria, removing by your desired key, then just use the foreach key. Example:

$keys_to_be_removed = array(14, 18);
foreach($songs as $key => $song) {
    if(in_array($key, $keys_to_be_removed)) {
        $song->parentNode->removeChild($song);
    }
}

Or just explicitly using indexing to delete without the foreach loop:

// starts at index zero
$first_song = $doc->getElementsByTagName('song')->item(0);
$songs = $doc->documentElement;
$songs->removeChild($first_song);
Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the tip about the ->removeChild(). But I'm not trying to remove my hated artists. Imagine there are 30 song elements in the songs root element. I just want to remove one of them based on the index. for example songs[14], songs[8], ect. How do I do this?
@SunnyD oh okay, just use the foreach key. remember though, this is starts from zero, so the first song will land on index zero. check my edit. i thought you wanted to delete your hated songs/artists, lol
@SunnyD i added another piece of info on my revision also, okay, i thought that was your criteria of removing :D, anyways im glad this helped
0
$songs = $doc->getElementsByTagName('song');

$songs.item(1).parentNode.removeChild($songs.item(1));
$songs.item(7).parentNode.removeChild($songs.item(7));
$songs.item(12).parentNode.removeChild($songs.item(12));

etc...

1 Comment

I tried this too but while it got rid of the error, its not deleting the element from the xml file...
0

XPath can select nodes by their index/position (it starts with 1). It will always return a node list that is traversable with foreach. The list will be empty if the index does not exists. To delete a node from the DOM you have to remove it from its parent node.

$xml = <<<'XML'
<songs>
   <song>
      <title>A</title>
      <artist>AA</artist>
   </song>
</songs>
XML;

$index = 1; // (int)$_GET['song'];

$doc = new DOMDocument();
$doc->loadXml($xml);
$xpath = new DOMXPath($doc);

foreach ($xpath->evaluate('//song['.$index.']') as $song) {
  $song->parentNode->removeChild($song);
}

echo $doc->saveXml();

Output:

<?xml version="1.0"?>
<songs>

</songs>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.