Как удалить тег XML на основе дочернего атрибута с помощью php?

У меня есть XML как ниже

<entries>
  <entry>
    <title lang="en">Sample</title>
    <entrydate>0</entrydate>
    <contents>0</contents>
    <entrynum>0</entrynum>
  </entry>
  <entry>
    <title lang="fr">Sample</title>
    <entrydate>1</entrydate>
    <contents>1</contents>
    <entrynum>1</entrynum>
  </entry>
</entries>

Есть ли в PHP способ удалить родительский узел (entry) на основании названия lang атрибут? Мне нужно оставить только en один, поэтому в этом случае мне нужно будет получить XML без второго entry узел.

Я попытался осмотреться, но не смог найти решения...

3 ответа

Решение

Вам нужно использовать DOMDocument класс для разбора строки в документ XML. Тогда используйте DOMXpathкласс, чтобы найти целевой элемент в документе и использовать DOMNode::removeChild() удалить выбранный элемент из документа.

$doc = new DOMDocument(); 
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
// select target entry tag
$entry = $xpath->query("//entry[title[@lang='fr']]")->item(0);
// remove selected element
$entry->parentNode->removeChild($entry);
$xml = $doc->savexml();

Вы можете проверить результат в демо

Вы также можете прочитать ваш файл и сгенерировать новый с вашей модификацией

<?php
$entries = array('title' => "What's For Dinner",
'link' => 'http://menu.example.com/',
'description' => 'Choose what to eat tonight.');
print "<entries>\n";
foreach ($entries as $element => $content) {
print " <$element>";
print htmlentities($content);
print "</$element>\n";
}
print "</entries>";
?>

Используйте метод, описанный в этом ответе, т.е.

<?php
$xml = simplexml_load_file('1.xml');

$del_items = [];
foreach ($xml->entry as $e) {
  $attr = $e->title->attributes();
  if ($attr && $attr['lang'] != 'en') {
    $del_items []= $e;
  }
}

foreach ($del_items as $e) {
  $dom = dom_import_simplexml($e);
  $dom->parentNode->removeChild($dom);
}

echo $xml->asXML();

Выход

<?xml version="1.0" encoding="UTF-8"?>
<entries>
  <entry>
    <title lang="en">Sample</title>
    <entrydate>0</entrydate>
    <contents>0</contents>
    <entrynum>0</entrynum>
  </entry>

</entries>

Элементы не могут быть удалены в первом цикле, потому что в противном случае мы можем разорвать цепочку итераций. Вместо этого мы собираем входные объекты в $del_items массив, а затем удалить их из XML в отдельном цикле.

Другие вопросы по тегам