2012-05-23 22 views
16

Tôi đang cố gắng phân tích cú pháp mã HTML bằng DOMDocument, thực hiện các công cụ như thay đổi đối với nó, sau đó lắp lại nó thành chuỗi mà tôi gửi đến đầu ra.Làm cách nào để làm cho HTML5 hoạt động với DOMDocument?

Nhưng có một vài vấn đề liên quan đến phân tích cú pháp, có nghĩa là những gì tôi gửi cho DOMDocument không phải lúc nào trở lại trong hình thức tương tự :)

Dưới đây là một danh sách:

  1. sử dụng ->loadHTML:

    • định dạng tài liệu của mình bất kể cài đặt preserveWhitespaceformatOutput (mất khoảng trắng trên văn bản được định dạng trước)
    • cho tôi lỗi khi tôi có các thẻ html5 như <header>, <footer> vv Nhưng chúng có thể bị chặn lại, vì vậy tôi có thể sống với điều này.
    • sản xuất đánh dấu không phù hợp - ví dụ nếu tôi thêm một yếu tố <link ... /> (với một thẻ tự đóng), sau khi phân tích cú pháp/saveHTML sản lượng sẽ được <link .. >
  2. sử dụng ->loadXML:

    • mã hóa các đối tượng như > từ <style> hoặc <script> thẻ: body > div trở thành body &gt; div
    • tất cả các thẻ đều đóng cùng một cách, ví dụ <meta ... /> trở thành <meta...></meta>; nhưng điều này có thể được sửa bằng regex.

Tôi không cố gắng HTML5lib nhưng tôi muốn DOMDocument thay vì một phân tích cú pháp tùy chỉnh cho lý do hiệu suất


Cập nhật:

Vì vậy, như Honeymonster đề cập bằng các bản sửa lỗi CDATA vấn đề chính với loadXML.

Có cách nào tôi có thể ngăn tự đóng tất cả các thẻ HTML trống bên cạnh một tập hợp nhất định mà không sử dụng regex không?

Ngay bây giờ tôi có:

$html = $dom->saveXML($node); 

$html = preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($matches){ 

     // ignore only these tags 
     $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta'); 

     // if a element that is not in the above list is empty, 
     // it should close like `<element></element>` (for eg. empty `<title>`) 
     return in_array($matches[1], $xhtml_tags) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>"; 
}, $html); 

mà hoạt động nhưng nó cũng sẽ làm việc thay thế trong nội dung CDATA, mà tôi không muốn ...

+3

Bạn có đoạn thử nghiệm mà chúng tôi có thể chơi cùng không? –

+0

Làm cách nào để biết html5lib chậm hơn DOMDocument nếu bạn thậm chí không thử nó? – Brad

+3

Tôi giả định rằng bởi vì nó được viết bằng PHP .. DOMDocument là một phần mở rộng PHP được viết bằng C – Alex

Trả lời

7

Thật không may, hoặc có thể là may mắn thay, DOMDocument được thiết kế để không cố gắng để duy trì định dạng từ văn bản gốc. Điều này là để làm cho trạng thái nội bộ của trình phân tích cú pháp dễ quản lý hơn bằng cách giữ cho tất cả các phần tử có cùng một kiểu. Hầu hết các trình phân tích cú pháp sẽ tạo ra một biểu diễn cây trong bộ nhớ và không lo lắng về việc định dạng văn bản cho đến khi người dùng yêu cầu như vậy.Đây là lý do tại sao các thẻ tự đóng của bạn là đầu ra với các thẻ đóng riêng biệt. Tin tốt là nó không quan trọng.

Đối với thẻ phong cách và các thẻ script nhận <> chuyển đổi sang &lt;&gt;, bạn có thể để tránh việc chuyển đổi bởi xung quanh các nội dung của nguyên tố này trong câu hỏi với các thẻ CDATA khuyến thusly:

<style> 
    /*<![CDATA[*/ 
    body > div { 
     width: 50%; 
    } 
    /*]]>*/ 
</style> 

Các bình luận /* */ xung quanh các khai báo cdata là cho phép các máy khách bị hỏng mà không biết về các phần cdata và thay vào đó xử lý các khai báo như mã CSS. Nếu bạn chỉ sử dụng tài liệu nội bộ, bạn có thể bỏ qua các chú thích /* */ và chỉ có khai báo cdata. Bạn có thể gặp phải vấn đề với các khách hàng bị hỏng nói trên nếu bạn thao tác tài liệu và sau đó gửi nó đến trình duyệt mà không cần kiểm tra để đảm bảo các chú thích /* */ được giữ lại; Tôi không chắc liệu domdocument có giữ lại hay không.

+1

wow tôi không thể tin rằng tôi đã không nghĩ đến việc sử dụng CDATA :) cảm ơn, giải quyết nhiều vấn đề với trình phân tích cú pháp xml, mà tôi muốn sử dụng;) – Alex

12

Sử dụng html5lib. Nó có thể phân tích cú pháp html5 và tạo ra một DOMDocument. Ví dụ:

require_once '/path/to/HTML5/Parser.php'; 
$dom = HTML5_Parser::parse('<html><body>...'); 

Documentation

+2

Nhưng html5lib có thể lưu lại tài liệu và trả lại chuỗi có định dạng đẹp? Tôi không thấy điều đó trong mã nguồn. – Wiliam

-4

Khi initialising DOMDocument, làm như sau:

$dom = new DOMDocument(5, 'UTF-8'); 
+1

Thật không may, tham số phiên bản không tham chiếu đến phiên bản HTML. – nibra

4

Nếu bạn muốn hỗ trợ HTML5, không chạm DOMDocument ở tất cả.

Hiện nay lựa chọn tốt nhất có vẻ là https://github.com/Masterminds/html5-php

Trước lựa chọn tốt nhất là https://github.com/html5lib/html5lib-php nhưng như mô tả nói, đó là "hiện bỏ dở". Và đây là trạng thái từ tháng 10 năm 2011 nên tôi không còn nín thở nữa.

Tôi chưa sử dụng html5-php trong sản xuất để tôi không thể cung cấp bất kỳ trải nghiệm thực tế nào về điều đó. Tôi đã sử dụng html5lib-php trong sản xuất và tôi sẽ nói rằng nó phân tích cú pháp các tài liệu được định dạng chính xác nhưng nó có lỗi không mong muốn với một số lỗi cú pháp đơn giản. Mặt khác, có vẻ như thực hiện thuật toán đại lý con nuôi và một số trường hợp góc kỳ lạ khác một cách chính xác. Nếu html5lib-php vẫn được duy trì, tôi vẫn thích nó hơn. Tuy nhiên, như mọi thứ hiện đang đứng, tôi muốn sử dụng html5-php và có thể giúp khắc phục các lỗi còn lại ở đó.

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