Удалить тег xml php

Удалить дочерний элемент с определенным атрибутом в SimpleXML для PHP

Мне нужно удалить определенный элемент seg с идентификатором «A12», как я могу это сделать? Я пробовал прокручивать элементы seg и отключать конкретный, но это не работает, элементы остаются.

18 ответов

Хотя SimpleXML предоставляет способ удаления узлов XML, возможности его модификации несколько ограничены. Еще одно решение — использовать расширение DOM. dom_import_simplexml() поможет вам преобразовать ваш SimpleXMLElement в DOMElement . Просто пример кода (протестирован с PHP 5.2.5):

$data='      '; $doc=new SimpleXMLElement($data); foreach($doc->seg as $seg) < if($seg['id'] == 'A12') < $dom=dom_import_simplexml($seg); $dom->parentNode->removeChild($dom); > > echo $doc->asXml(); 
$segs=$doc->xpath('//seq[@id="A12"]'); if (count($segs)>=1) < $seg=$segs[0]; >// same deletion procedure as above 

Спасибо за это — изначально я был склонен избегать этого ответа, так как я хотел избежать использования DOM. Я попробовал несколько других ответов, которые не сработали, прежде чем, наконец, попробовать ваш — который работал безупречно. Любой, кто рассматривает возможность избежать этого ответа, сначала попробуйте его и посмотрите, не получается ли он именно то, что вы хотите. Я думаю, что меня оттолкнуло то, что я не осознавал, что dom_import_simplexml () по-прежнему работает с той же базовой структурой, что и simplexml, поэтому любые изменения в одном сразу влияют на другой, не нужно писать / читать или перезагружать.

Читайте также:  Python чем отличается итератор от генератора

Обратите внимание, что этот код удалит только первый встреченный элемент. Я подозреваю, что это потому, что изменение данных во время итерации делает недействительной позицию итератора, что приводит к завершению цикла foreach. Я решил эту проблему, сохранив dom-импортированные узлы в массиве, который затем перебрал, чтобы выполнить удаление. Не очень хорошее решение, но оно работает.

На самом деле вы можете удалить элементы SimpleXML, используя unset, но это в моем ответе;) stackoverflow.com/a/16062633/367456

Вопреки распространенному мнению в существующих ответах, каждый элемент Simplexml node может быть удален из документа сам по себе и unset() . Дело в том, что вам просто нужно понять, как работает SimpleXML.

Сначала найдите элемент, который хотите удалить:

list($element) = $doc->xpath('/*/seg[@id="A12"]'); 

Затем удалите элемент, представленный в $element , вы отключите его самоописание:

Это работает, потому что первым элементом любого элемента является сам элемент в Simplexml (самореклама). Это связано с его магической природой, числовые индексы представляют элементы в любом списке (например, parent- > children), и даже один из них является таким списком.

Номера числовых индексов строки представляют атрибуты (в массиве) или дочерние элементы (в свойствах).

Поэтому числовые индексы в свойстве-доступ вроде:

Естественно, что этот пример xpath довольно прямолинейный (в PHP 5.4):

       DATA; $doc = new SimpleXMLElement($data); unset($doc->xpath('seg[@id="A12"]')[0]->); $doc->asXml('php://output'); 

Очень хорошо объяснил ответ. Одна деталь, которую я не сразу оценил, это то, что вы не можете просто вывести XPath из цикла, потому что удаление элемента внутри обычного цикла foreach ( $doc->seg as $seg ) сбивает с толку итератор (эмпирическое правило: don не изменяйте длину итератора в середине цикла). Реализация SimpleXML в XPath не имеет этой проблемы, потому что ее результаты представляют собой обычный массив несвязанных элементов.

@IMSoP: Для любого Traversable и этот вопрос (живые списки), я настоятельно рекомендую iterator_to_array в SimpleXML итераторов установить ключевой параметр FALSE , поскольку SimpleXMLElement использует имя-тег , как ключ , который часто является продублировать в таком перечислении , а затем эту функцию будет возвращать только последний из этих одноименных узлов, если второй параметр не FALSE .

$str = STR; $xml = simplexml_load_string($str); unset($xml –> a –> b –> c); // this would remove node c echo $xml –> asXML(); // xml document string without node c 

Это работает, только если имя узла уникально в наборе. Если это не так, вы в конечном итоге удаляете все узлы с одинаковыми именами.

@Dallas: Даллас: То, что вы комментируете, правильно, но оно также содержит решение. Как получить доступ только к первому элементу? Смотрите здесь: stackoverflow.com/a/16062633/367456

Я считаю, что ответ Стефана прав. Если вы хотите удалить только один node (а не все совпадающие узлы), вот еще один пример:

//Load XML from file (or it could come from a POST, etc.) $xml = simplexml_load_file('fileName.xml'); //Use XPath to find target node for removal $target = $xml->xpath("//seg[@id=$uniqueIdToDelete]"); //If target does not exist (already deleted by someone/thing else), halt if(!$target) return; //Returns null //Import simpleXml reference into Dom & do removal (removal occurs in simpleXML object) $domRef = dom_import_simplexml($target[0]); //Select position 0 in XPath array $domRef->parentNode->removeChild($domRef); //Format XML to save indented tree rather than one line and save $dom = new DOMDocument('1.0'); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML($xml->asXML()); $dom->save('fileName.xml'); 

Обратите внимание, что разделы Load XML. (first) и Format XML. (последний) могут быть заменены другим кодом в зависимости от того, откуда взялись ваши XML-данные и что вы хотите делать с выходом; это промежутки между ними, которые находят node и удаляют его.

Кроме того, оператор if существует только для того, чтобы убедиться, что объект node существует, прежде чем пытаться его переместить. Вы можете выбрать различные способы обработки или игнорирования этого случая.

Обратите внимание, что xpath () возвращает пустой массив, если ничего не найдено, поэтому проверка $ target == false должна быть пустой ($ target). +1 за решение xpath

Если вы расширяете базовый класс SimpleXMLElement, вы можете использовать этот метод:

class MyXML extends SimpleXMLElement < public function find($xpath) < $tmp = $this->xpath($xpath); return isset($tmp[0])? $tmp[0]: null; > public function remove() < $dom = dom_import_simplexml($this); return $dom->parentNode->removeChild($dom); > > // Example: removing the element with = new MyXML(''); $foo->find('//bar[@id="1"]')->remove(); print $foo->asXML(); //  

Он подвержен Fatal error: Call to a member function remove() on null каждый раз, когда $foo->find(‘//bar[@id=»1″]’) возвращает null .

$data = '     '; $doc = new SimpleXMLElement($data); $segarr = $doc->seg; $count = count($segarr); $j = 0; for ($i = 0; $i < $count; $i++) < if ($segarr[$j]['id'] == 'A12') < unset($segarr[$j]); $j = $j - 1; >$j = $j + 1; > echo $doc->asXml(); 

Чтобы удалить/сохранить узлы с определенным значением атрибута или попадать в массив значений атрибутов, вы можете расширить класс SimpleXMLElement как это (самая последняя версия в моем GitHub Gist):

class SimpleXMLElementExtended extends SimpleXMLElement < /** * Removes or keeps nodes with given attributes * * @param string $attributeName * @param array $attributeValues * @param bool $keep TRUE keeps nodes and removes the rest, FALSE removes nodes and keeps the rest * @return integer Number o affected nodes * * @example: $xml->o->filterAttribute('id', $products_ids); // Keeps only nodes with id attr in $products_ids * @see: http://stackoverflow.com/questions/17185959/simplexml-remove-nodes */ public function filterAttribute($attributeName = '', $attributeValues = array(), $keepNodes = TRUE) < $nodesToRemove = array(); foreach($this as $node) < $attributeValue = (string)$node[$attributeName]; if ($keepNodes) < if (!in_array($attributeValue, $attributeValues)) $nodesToRemove[] = $node; >else < if (in_array($attributeValue, $attributeValues)) $nodesToRemove[] = $node; >> $result = count($nodesToRemove); foreach ($nodesToRemove as $node) < unset($node[0]); >return $result; > > 

Затем, используя ваш XML- $doc вы можете удалить свой узел :

$data='      '; $doc=new SimpleXMLElementExtended($data); $doc->seg->filterAttribute('id', ['A12'], FALSE); 

или удалить несколько узлов :

$doc->seg->filterAttribute('id', ['A1', 'A12', 'A29'], FALSE); 

Для сохранения только и узлов и удаления остальных:

$doc->seg->filterAttribute('id', ['A5', 'A30'], TRUE); 

Источник

Regex to remove an HTML tag and its content from PHP string

We use the in-built PHP strip_tags() function to remove HTML, XML, and PHP tags from a PHP string.

Example

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

"; echo strip_tags($mystring);

Lorem IpsumLorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

As you can see, it removes all the HTML tags and their attributes but retains all the content of those tags.

How to retain only specified tags

The strip_tags() function allows for a second optional argument for specifying allowable tags to be spared when the rest HTML tags get stripped off. This way, you can retain some and remove all the other tags.

Example

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

"; echo strip_tags($mystring,"

,

");

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

As you can see the rest of the tags have been removed leaving the string with only the and

, which were specified in the second argument.

How to remove certain tags with all their content

As opposed to the above examples where only tags are removed but their content remains intact, let’s see how we can do away with specific tags together with their content.

To achieve this we use the PHP preg_replace() function.

The first argument is the regular expression(we specify the tag(s) that we want to remove or replace in it), the second is the match(this is what we replace the specified tag(s) with) and the third is the string in which we want to make changes to.

Replace the terms «tag» with the respective opening and closing tags you wish to remove and $str with your string. These tags in the string will get replaced with whatever you set as the second argument, in this case, removed since we have used empty quotes «» .

Example

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

"; echo preg_replace('~~Usi', "", $mystring);

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

We have removed the tag and its content as specified in the function.

If you would like to strip off multiple tags with their content at a go, you can specify them as an array of regular expressions in the first argument of the function.

Example

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec volutpat ligula.

"; echo preg_replace(array('~~Usi','~~Usi','~~Usi'), "", $mystring);

Lorem sit amet, adipiscing elit. Donec nec volutpat ligula.

We have specified an array of , and , all which together with their content have been striped off.

That’s all for this article.

Источник

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

Есть ли в 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(); 

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

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

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

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

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(); 

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

Источник

Оцените статью