Max879
Max879

Reputation: 11

Remove child from XML with PHP DOM

I want to remove first video element (video src=time.mp4) from this xml (filename.xml) and save the xml into filename4.smil :

<?xml version="1.0" encoding="utf-8"?>
<smil>
  <stream name="mysq"/>
  <playlist name="Default" playOnStream="mysq" repeat="true" scheduled="2010-01-01 01:01:00">
    <video src="time.mp4" start="0" length="-1"> </video>
    <video src="sample.mp4" start="0" length="-1"> </video>
  </playlist>
</smil>

i am using this code, but is not working:

<?php 


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

$thedocument = $doc->documentElement; 

//this gives you a list of the messages 
$list0 = $thedocument->getElementsByTagName('playlist'); 
$list = $list0->item(0);


$nodeToRemove = null; 
foreach ($list as $domElement){ 
$videos = $domElement->getElementsByTagName( 'video' );
$video = $videos->item(0);
    $attrValue = $video->getAttribute('src'); 
    if ($attrValue == 'time.mp4') { 
    $nodeToRemove = $videos; //will only remember last one- but this is just an example :) 


    } 

} 

//Now remove it. 
if ($nodeToRemove != null) 
$thedocument->removeChild($nodeToRemove); 

$doc->save('filename4.smil');

?>

Upvotes: 0

Views: 871

Answers (2)

ThW
ThW

Reputation: 19502

Using Xpath expressions you can fetch video nodes with a specific src attribute, iterate them and remove them.

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);

$expression = '/smil/playlist/video[@src="time.mp4"]';
foreach ($xpath->evaluate($expression) as $video) {
    $video->parentNode->removeChild($video);
}

var_dump($document->saveXML());

It is possible to fetch nodes by position as well: /smil/playlist/video[1].

Upvotes: 0

Nigel Ren
Nigel Ren

Reputation: 57131

Assuming that there is only 1 playlist item and you want to remove the first video element from that, here are 2 methods.

This one uses getElementsByTagName() as you are in your code, but simple picks the first item from each list and then removes the item (you have to use parentNode to remove the child node).

$playlist = $doc->getElementsByTagName('playlist')->item(0);
$video = $playlist->getElementsByTagName( 'video' )->item(0);
$video->parentNode->removeChild($video);

This version uses XPath, which is more flexible, it looks for the playlist elements with a video element somewhere inside. Again, just taking the first one and removing it...

$xp = new DOMXPath($doc);
$video = $xp->query('//playlist//video')->item(0);
$video->parentNode->removeChild($video);

The problem with

$thedocument->removeChild($nodeToRemove);

is that you are trying to remove a child element from the base document. As this node is nested in the hierarchy, it won't be able to remove it, you need to remove it from it's direct parent.

Upvotes: 2

Related Questions