2013-04-10 44 views
9

Tôi đã sử dụng @Alex's approach here để xóa thẻ tập lệnh khỏi tài liệu HTML bằng DOMDocument được tích hợp sẵn. Vấn đề là nếu tôi có một thẻ script với nội dung Javascript và sau đó một thẻ script khác liên kết đến một tệp nguồn Javascript bên ngoài, không phải tất cả các thẻ script đều bị xóa khỏi HTML.DOMDocument xóa thẻ tập lệnh khỏi nguồn HTML

$result = ' 
<!doctype html> 
<html> 
    <head> 
     <meta charset="utf-8"> 
     <title> 
      hey 
     </title> 
     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
     <script> 
      alert("hello"); 
     </script> 
    </head> 
    <body>hey</body> 
</html> 
'; 

$dom = new DOMDocument(); 
if($dom->loadHTML($result)) 
{ 
    $script_tags = $dom->getElementsByTagName('script'); 

    $length = $script_tags->length; 

    for ($i = 0; $i < $length; $i++) { 
     if(is_object($script_tags->item($i)->parentNode)) { 
      $script_tags->item($i)->parentNode->removeChild($script_tags->item($i)); 
     } 
    } 

    echo $dom->saveHTML(); 
} 

Các đầu ra mã trên:

<html> 
    <head> 
     <meta charset="utf-8"> 
     <title>hey</title> 
     <script> 
     alert("hello"); 
     </script> 
    </head> 
    <body> 
     hey 
    </body> 
</html> 

Như bạn có thể thấy từ kết quả, chỉ có thẻ script bên ngoài đã được gỡ bỏ. Tôi có thể làm gì để đảm bảo tất cả các thẻ tập lệnh đều bị xóa không?

Trả lời

19

Lỗi của bạn thực sự không đáng kể. Một đối tượng DOMNode (và tất cả các hậu duệ của nó - DOMElement, DOMNodeList và một số khác!) Được tự động cập nhật khi phần tử mẹ thay đổi, đáng chú ý nhất là khi số lượng con của nó thay đổi. Điều này được viết trên một vài dòng trong tài liệu PHP, nhưng chủ yếu được quét dưới thảm.

Nếu bạn lặp sử dụng ($k instanceof DOMNode)->length và sau đó xóa các phần tử khỏi các nút, bạn sẽ nhận thấy rằng thuộc tính length thực sự thay đổi! Tôi đã phải viết thư viện của riêng mình để chống lại điều này và một vài điều kỳ quặc khác.

Giải pháp:

if($dom->loadHTML($result)) 
{ 
    while (($r = $dom->getElementsByTagName("script")) && $r->length) { 
      $r->item(0)->parentNode->removeChild($r->item(0)); 
    } 
echo $dom->saveHTML(); 

Tôi không thực sự lặp - chỉ popping phần tử đầu tiên cùng một lúc. Kết quả: http://sebrenauld.co.uk/domremovescript.php

+0

Điều đó có hiệu quả, cảm ơn! – RandomCoder

+6

Một giải pháp khác là chỉ lặp qua các phần tử theo thứ tự ngược lại. – CBroe

4

Để tránh điều đó bạn sẽ có được sự ngạc nhiên của một live danh sách nút - mà được ngắn hơn khi bạn xóa các nút - bạn có thể làm việc với một bản sao vào một mảng sử dụng iterator_to_array:

foreach(iterator_to_array($dom->getElementsByTagName($tag)) as $node) { 
    $node->parentNode->removeChild($node); 
}; 
+1

Tuyệt vời, cảm ơn. – Jonathan

+0

+1 đơn giản hơn nhiều so với câu trả lời được chấp nhận - có vẻ như sử dụng 'iterator_to_array()' trên danh sách nút về cơ bản là phải khi bạn duyệt qua tài liệu để thực hiện thay đổi. –

Các vấn đề liên quan