2016-11-07 290 views
0

根據DOMDocument::getElementsByTagName的文檔,我可以用"*"參數調用該函數,並從某些HTML代碼中獲取所有HTML元素的列表。如何獲取PHP中所有html元素的列表?

然而,用下面的代碼:

<?php 
    $dom = new DOMDocument(); 
    $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
    $nodes = $dom->getElementsByTagName("*"); 

    foreach ($nodes as $node) { 
    $new_text= new DOMText($node->textContent."MODIFIED"); 

    $node->removeChild($node->firstChild); 
    $node->appendChild($new_text); 
    } 
    $content = $dom->saveHTML(); 
    echo $content; 
?> 

我得到的只有一個元素的列表,上面的代碼的執行結果是:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html>hellobyeMODIFIED</html> 

,而我希望的東西像這樣:

<html><body><div>helloMODIFIED</div><div>byeMODIFIED</div></body></html> 

不應該DOMDocument::getElementsByTagName方法返回一個儘可能多的HTML元素在HTML代碼中可用?

注:我需要顯式創建DOMText實例,因爲我需要這個在PHP 5.4中工作。 DOMNode::textContent只能從PHP寫入5.6

+0

你的元素具有相同的標籤名稱... – Alexis

+0

@Alexis,是的,但如果我的getElementsByTagName被改變的getElementsByTagName( 「*」)( 「分區」) ,那麼我得到我想要的結果,並且這些元素仍然具有相同的標籤名稱。 –

+0

@MarcosFernandez,你不清楚你到底想要達到什麼目的。你想修改所有文本節點嗎?還是要修改具有文本節點的葉子(最後一個標籤)的所有文本節點?例如,這個序列應該如何修改'

textabcdef
'? –

回答

2

DOMDocument::getElementsByTagName方法實際上會返回所有標記,如果第一個參數是'*'。但是你的代碼在第一次迭代時用一個文本節點代替<body>標籤(包括所有子節點)。

迭代的節點,並修改只有nodeType屬性等於XML_TEXT_NODE節點:

$nodes = $dom->getElementsByTagName('*'); 

foreach ($nodes as $node) { 
    for ($child = $node->firstChild; $child; $child = $child->nextSibling) { 
    if (! ($child->nodeType === XML_TEXT_NODE && trim($child->textContent))) { 
     continue; 
    } 

    // The textContent is writable since PHP 5.6.1 
    if (PHP_VERSION_ID >= 50601) { 
     $child->textContent .= 'MODIFIED'; 
     continue; 
    } 

    // For older versions, create DOMText explicitly 
    $text = new DOMText($child->textContent . 'MODIFIED'); 
    try { 
     if ($child->parentNode->replaceChild($text, $child)) 
     $child = $text; 
    } catch (Exception $e) { 
     trigger_error("Failed to modify text '$child->textContent': " 
     . $e->getMessage(), E_USER_WARNING); 
    } 
    } 
} 

echo $dom->saveHTML(); 

注意,對於PHP版本5.6.1和更新,你不需要明確創建DOMText情況下,因爲DOMNode::textContent屬性可供讀取和寫入。所以你可以簡單地通過給這個屬性賦一個字符串值來修改文本。只確保節點除XML_TEXT_NODE之外沒有子節點。

上述檢查的代碼,如果trim($child->textContent)不爲空,因爲文檔可以包含額外的空間字符(包括換行),例如:

<div><!-- newline/spaces --> 
    <span>text</span><!-- newline/spaces --> 
</div><!-- newline/spaces --> 
+0

謝謝,這(幾乎)它!只有一件事:我確實需要明確創建DOMText實例,因爲我需要這個在PHP 5.4中工作。 'DOMNode :: textContent'只能從PHP 5.6開始編寫。 5.4仍然無法完成這項工作。 –

+0

@MarcosFernandez,更新了答案 –

+0

非常感謝!我被困在了child-> parentNode的東西里。並感謝你的好解釋。很多時間保存! –

0

嘗試這種情況: -

foreach($dom->getElementsByTagName('*') as $element){ 

} 
0

此功能' DOMDocument :: getElementsByTagName'返回包含所有元素的DOMNodeList類的新實例。

,它工作正常:

<?php 
$dom = new DOMDocument(); 
    $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
    $nodes = $dom->getElementsByTagName("*"); 

    foreach ($nodes as $node) { 
     echo $node->tagName."<br />"; 
    } 
?> 

其輸出文檔的所有標籤。

也許你需要像水木清華:

<?php 


    $dom = new DOMDocument(); 
     $dom->loadHTML("<html><body><div>hello</div><div>bye</div></body></html>"); 
     $nodes = $dom->getElementsByTagName("*"); 

     foreach ($nodes as $node) { 
      if ($node->tagName=='div'){ 
      $node->nodeValue .= "new content"; 
      } 
     } 

     $content = $dom->saveHTML(); 
     echo htmlspecialchars($content); 

?>