2013-06-19 2 views
1

У меня есть цикл foreach, который работает только один раз, и он меня озадачивает.SimpleXML удаляет узлы

1: загружаю массив значений состояния (либо «запроса», «удалить», или «купил»)

2: Затем я загрузить файл XML и нужно перебрать «код» узлов и обновлять свой статус, НО если новый код «удалить» Я хочу, чтобы удалить его, прежде чем перейти на следующий один

структуры XML является ....

<content> 
.... lots of stuff 
<codes> 
<code date="xxx" status="request">xxxxx</code> 
.. repeat ... 
</codes> 
</content> 

и код РНР .. .

$newstatus = $_POST['updates']; 
$file = '../apps/templates/'.$folder.'/layout.xml'; 
$xml2 = simplexml_load_file($file); 
foreach($xml2->codes->code as $code){ 
    if($code['status'] == "delete") { 
     $dom=dom_import_simplexml($code); 
     $dom->parentNode->removeChild($dom); 
    } 
} 
$xml2->asXml($file); 

Я временно удалил обновление, чтобы отладить проверку удаления. Все это работает, но только удаляет 1-е удаление и оставляет все остальные удаления, даже если это петля foreach ??. Любая помощь очень ценится.

+0

Повторяющийся вопрос, проверьте ответ на http://stackoverflow.com/questions/3418197/how-to-remove-a-node-if-it-exists-with-simplexml?rq=1. –

+0

Скорее всего, вы были скопированы над этим кодом из [принятого ответа (прямо сейчас)] (http://stackoverflow.com/a/262556/367456) из * [Удалить ребенка с определенным атрибутом в SimpleXML для PHP] (http://stackoverflow.com/q/262351/367456) *. Проблема в том, что данный ответ неустойчив. Проблема с этим кодом заключается в том, что он написан для одного удаления только после удаления итератора. Вам нужно преобразовать его в массив сначала либо с помощью 'iterator_to_array', либо в случае simplexml, в частности с помощью xpath. http://stackoverflow.com/a/16062633/367456 – hakre

ответ

13

Удаление нескольких раз в одной итерации неустойчиво. Например. если вы удалите второй элемент, третий станет вторым и так далее.

Вы можете предотвратить это путем накопления элементов для удаления в массив первых:

$elementsToRemove = array(); 
foreach ($xml2->codes->code as $code) { 
    if ($code['status'] == "delete") { 
     $elementsToRemove[] = $code; 
    } 
} 

А потом удалить элемент на основе массива, который является стабильным, пока вы итерацию над ней:

foreach ($elementsToRemove as $code) { 
    unset($code[0]); 
} 

Вы также можете поместить условие if в запрос xpath, который возвращает массив непосредственно (см. Пример the duplicate question) или используя iterator_to_array().

+1

Это действительно полезный ответ. Я дважды был в этой ситуации, и оба раза это спасло меня. Возможно, в следующий раз я смогу запомнить это ... – PaulSkinner

+0

Спасибо за это, он работал с таким кодом. ** $ xml = новый SimpleXMLElement ($ rs_xml); $ elementsToRemove = array(); foreach ($ xml-> channel-> item as $ element) { if ($ element-> guid == "http://www.EXAMPLE.com/?p=2385281") { $ elementsToRemove [] = $ элемент; } } foreach ($ elementsToRemove as $ code) { unset ($ code [0]); } ** – ziggrat

Смежные вопросы