Вот XML-файл, над которым я работаю:
<list>
<activity>swimming</activity>
<activity>running</activity>
<activity>soccer</activity>
</list>
Страница index.php, которая показывает список действий с флажками, кнопку для удаления отмеченных действий и поле для добавления новых действий:
<html>
<head></head>
<body>
<?php
$xmldoc = new DOMDocument();
$xmldoc->load('sample.xml', LIBXML_NOBLANKS);
$count = 0;
$activities = $xmldoc->firstChild->firstChild;
//prints the list of activities, with checkboxes on the left for each item
//the $count variable is the id to each entry
if ($activities!=null){
echo '<form name=\'erase\' action=\'delete.php\' method=\'post\'>' . "\n";
while($activities!=null){
$count++;
echo " <input type=\"checkbox\" name=\"activity[]\" value=\"$count\"/>";
echo ' '.$activities->textContent.'<br/>'."\n";
$activities = $activities->nextSibling;
}
echo ' <input type=\'submit\' value=\'erase selected\'>';
echo '</form>';
}
?>
//section used for inserting new entries. this feature is working as expected.
<form name='input' action='insert.php' method='post'>
insert activity:
<input type='text name='activity'/>
<input type='submit' value='send'/>
<br/>
</form>
</body>
</html>
файл delete.php, который не работает должным образом:
<?php
$xmldoc = new DOMDocument();
$xmldoc->load('sample.xml', LIBXML_NOBLANKS);
$atvID = $_POST['activity'];
foreach($atvID as $id){
$delnode = $xmldoc->getElementsByTagName('activity');
$xmldoc->firstChild->removeChild($delnode->item($id));
}
$xmldoc->save('sample.xml');
?>
Я протестировал процедуру удаления без цикла, используя жестко заданный произвольный идентификатор, и она сработала. Я также протестировал массив $ atvID, и он правильно распечатал выбранные номера идентификаторов. Когда он находится внутри цикла, он выводит ошибку:
Catchable fatal error: Argument 1 passed to DOMNode::removeChild() must be an instance of DOMNode, null given in /directorypath/delete.php on line 9
Что не так с моим кодом?






элементы DOMNodeList индексируются, начиная с 0; Вам нужно переместить $ count ++ в конец цикла while на шаге вывода.
В дополнение к перемещению $ count ++ в конец цикла while было бы неплохо проверить delete.php, чтобы убедиться, что $ _POST ['activity'] является числовым и находится в указанном диапазоне, просто чтобы убедиться, что на вашей странице нет сообщений о фатальных ошибках.
Как мне сделать проверку?
Сложность DOMNodeLists заключается в том, что они НЕ являются массивами. Если вы удалите узел, список будет переиндексирован. Это приведет к поломке вашего кода, если пользователь выберет более одного элемента для удаления. Если вы выбрали плавание и бег, плавание и футбол будут удалены.
Возможно, вы захотите начать с присвоения каждому действию уникального идентификатора, который вы можете искать, скажем, атрибута с именем 'id' (это, вероятно, не будет настоящим идентификатором. GetElementByID () DOM работает только для XML, у которого есть DTD, например HTML-страница. Полагаю, вы не хотите туда идти.)
Вы можете обновить свой XML, чтобы он выглядел так.
<list>
<activity name = "swimming">swimming</activity>
<activity name = "running">running</activity>
<activity name = "soccer">soccer</activity>
</list>
Вы бы использовали эти атрибуты имени вместо $ count в качестве значения внутри ваших флажков.
Затем вы можете использовать xPath, чтобы найти элементы, которые нужно удалить внутри вашего foreach.
$xpath = new DOMXPath($xmldoc);
$xmldoc->firstChild->removeChild($xpath->query("/list/activity[@name='$id']")->item(0));
Надеюсь, это поможет вам начать работу.
Интересно. Как вы догадались, у меня возникли проблемы с удалением сразу нескольких записей именно из-за переиндексации DOM. Я решил эту проблему более простым способом, я начал удаление с самого большого идентификатора. Это сработало, но ваше решение заставило меня задуматься о xpath, я посмотрю на это.
Я получил ту же ошибку в новой кодовой базе, которую пробовал сегодня. Это начало заставлять меня помещать XML в одну из моих самых ненавистных вещей для отладки.