2011-01-13 2 views
7

Я пытаюсь удалить определенные ссылки в зависимости от их тега ID, но оставьте содержание ссылки. Например, я хочу, чтобы превратитьPHP Dom Удалить элемент оставить содержимое

Some text goes <a href="http://www.domain.tdl/" id="remove">here</a> 

в

Some text goes here 

Я попытался с помощью ниже.

$dom = new DOMDocument; 
$dom->loadHtml(mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8")); 
$xp = new DOMXPath($dom); 

foreach($xp->query('//a[contains(@id="remove")]') as $oldNode) { 
$revised = strip_tags($oldNode); 
} 

$revised = mb_substr($dom->saveXML($xp->query('//body')->item(0)), 6, -7, "UTF-8"); 
echo $revised; 

примерно взяты из here, но он просто выплевывает обратно одинаковое содержание $html.

Любая идея о том, как я это достигню?

+0

Вы не изменяете свой документ здесь, поэтому он использует один и тот же контент. Например, вы предоставили вызовы 'replaceChild' на объекте DOM, и вы просто создаете переменную, которую вы позже перезаписываете выводом' saveXML' –

+0

Хороший вопрос, +1. См. Мой ответ одного решения выражения XPath, который выбирает именно нужные узлы. :) –

ответ

12

Это моя функция для этого:

function DOMRemove(DOMNode $from) { 
    $sibling = $from->firstChild; 
    do { 
     $next = $sibling->nextSibling; 
     $from->parentNode->insertBefore($sibling, $from); 
    } while ($sibling = $next); 
    $from->parentNode->removeChild($from);  
} 

Так что:

$dom->loadHTML('Hello <a href="foo"><span>World</span></a>'); 
$a = $dom->getElementsByTagName('a')->item(0); // get first 
DOMRemove($a); 

Если вам:

Hello <span>World</span> 

Чтобы получить узлы с определенным ID, с помощью XPath:

$xpath = new DOMXpath($dom); 
$node = $xpath->query('//a[@id="something"]')->item(0); // get first 
DOMRemove($node); 
+0

Я посмотрел этот код на другое сообщение, которое вы сделали, но a) Я получаю сообщение об ошибке «Неустранимая ошибка: вызов функции-члена insertBefore() для не-объекта» и b) Как бы я адаптировал это для удалить только элементы с определенным идентификатором? – Jack

+0

@Jack: Извините, мой аргумент функции был '$ from', а не' $ node'. Исправлена. Спасибо что подметил это. Также добавлен пример для извлечения узла с определенным «id». – netcoder

+0

Два вопроса; Как вывести пересмотренные данные? И когда я использую пример, который вы указали для определенных идентификаторов, я получаю ту же ошибку, что и раньше. – Jack

1

Применение:

//a[@id='remove']/node() 
| 
//*[a[@id='remove']]/node()[not(self::a[@id=''remove])] 

Это выбирает все дети любого a, имеющего атрибут id со значением "remove" и всех предыдущих и последующих братьев этого a, которые сами по себе не другой a, имеющий атрибут id со значением "remove"

2

Подход, аналогичный ответу @ netcoder, но использующий другую структуру цикла и методы DOMElement.

$html = '<html><body>This <a href="http://www.domain.tdl/" id="remove">link</a> was removed.</body></html>'; 
$dom = new DOMDocument(); 
$dom->loadHTML($html); 
$xpath = new DOMXPath($dom); 
foreach ($xpath->query('//a[@id="remove"]') as $link) { 
    // Move all link tag content to its parent node just before it. 
    while($link->hasChildNodes()) { 
    $child = $link->removeChild($link->firstChild); 
    $link->parentNode->insertBefore($child, $link); 
    } 
    // Remove the link tag. 
    $link->parentNode->removeChild($link); 
} 
$html = $dom->saveXML(); 
+0

Can '$ child = $ link-> removeChild ($ link-> firstChild);' просто записываться как '$ child = $ link-> firstChild;'? – myol

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