2012-04-26 5 views
5

Theo mặc định lxml không understsand thẻ wbr, được sử dụng để thêm từ ngắt trong các từ dài. Nó định dạng nó là <wbr></wbr> khi nó được định dạng đơn giản là <wbr>, tương tự như thẻ br.lxml và <wbr> thẻ

Làm cách nào để thêm hành vi này vào lxml?

+1

Tôi không chắc chắn về đơn đăng ký của bạn, nhưng bạn có thể chỉ cần xóa thẻ đóng? –

Trả lời

10

Trên thực tế nó không phải là khó khăn để libxml2 vá (hướng dẫn này đã được thực hiện trên Ubuntu 11.04 với Python 2.7.3)

Đầu tiên xác định một chương trình thử nghiệm wbr_test.py:

from lxml import etree 
from cStringIO import StringIO 

wbr_html = """\ 
<html> 
    <head> 
    <title>wbr test</title> 
    </head> 
<body> 
    Test for a breakable<wbr>word implemenation change 
</body> 
</html> 
""" 

parser = etree.HTMLParser() 
tree = etree.parse(StringIO(wbr_html), parser) 

result = etree.tostring(tree.getroot(), 
         pretty_print=True, method="html") 
if result.split() != wbr_html.split(): # split, as we are not interested in whitespace differences 
    print(result) 
    print("not ok") 
else: 
    print("OK") 

Hãy chắc chắn rằng nó không thành công bởi đang chạy python wbr_test.py. Bạn nên chèn <\wbr> trước <\body> và in not ok ở cuối.

Tải về, giải nén và biên dịch libxml2:

wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz 
tar xvf libxml2-2.8.0.tar.gz 
cd libxml2-2.8.0/ 
./configure --prefix=/usr 
make -j8 # adjust number to match your number of cores 

Cài đặt, và cài đặt bindings python libxml2:

sudo make install 
cd to_python_bindings 
sudo python setup.py install 

thử nghiệm của bạn wbr_test.py một lần nữa, để chắc chắn rằng nó không thành công với phiên bản libxml2 mới nhất.

Trước tiên, hãy sao chép HTMLparser.c ví dụ: trong /var/tmp.

Bây giờ, hãy chỉnh sửa tệp HTMLparser.c ở mức toplevel của nguồn libxml2. Tìm kiếm từ forced (chỉ một lần xuất hiện). Bạn sẽ có định nghĩa thẻ <br>. Sao chép ba dòng bắt đầu bằng dòng bạn vừa tìm thấy.Điểm chèn phù hợp nhất là ngay trước khi kết thúc (sau khi định nghĩa của <var>). Để có được dấu phẩy cuối cùng bên phải trong bảng, hãy chèn ba dòng trước một dòng chỉ với '}' không phải là dấu phẩy với '};'.

Trong mã vừa được chèn Thay thế br bằng wbr và thay đổi DECL clear_attrs thành NULL (giả định rằng thẻ mới không có thuộc tính không dùng nữa).

Kết quả sẽ diff với các phiên bản trong /var/tmp (diff -u HTMLparser.c /var/tmp) như sau:

@@ -1039,6 +1039,9 @@ 
}, 
{ "var", 0, 0, 0, 0, 0, 0, 1, "instance of a variable or program argument", 
DECL html_inline, NULL, DECL html_attrs, NULL, NULL 
+}, 
+{ "wbr", 0, 2, 2, 1, 0, 0, 1, "possible line break ", 
+ EMPTY , NULL , DECL core_attrs, NULL , NULL 
} 
}; 

Make và cài đặt:

make && sudo make install 

thử nghiệm của bạn wbr_test.py một lần nữa. Nên hiển thị OK

+0

Rất tuyệt! Bạn có thể xác nhận không có cách nào để có được kết quả tương tự chỉ với cấu hình thời gian chạy không? – bukzor

+0

Một cách khác để cụm từ cùng một câu hỏi: không libxml2 không cho phép cấu hình thời gian chạy của danh sách mà bạn đã vá? – bukzor

+0

Tôi thực sự tự hỏi liệu điều đó có thể thực hiện được với libxml2 mà không tái cơ cấu nguồn. Các định nghĩa nằm trong một bảng yếu tố const tĩnh, mà không * không * được sao chép vào một cấu trúc động hơn, nhưng được sử dụng như là. Không thể thêm các mục vào bảng như vậy từ C, do đó không phải từ Python. – Anthon

3

<wbr> chỉ tồn tại trong HTML5, tôi nghi ngờ Điều phải làm là sử dụng lxml.html.html5parser.

Trong số đó, danh sách các thẻ trống được xác định bằng mã Python thông thường, vì vậy bạn luôn có thể chỉ cần nhập vào thẻ đó; xem lxml.html.defs.empty_tags. Các bản vá được chào đón, tôi chắc chắn. :)

+0

Tôi đã thử monkeypatching, không có hiệu lực. – bukzor

+0

@bukzor: 'br' cũng nằm trong 'special_inline_tags' ... bạn có thể cần phải" nhảy "wp vào đó. –

+1

Bạn có thể phải nhập 'defs' trước và monkeypatch nó trước khi nhập bất cứ điều gì khác trong lxml, hoặc các mô-đun khác sẽ nhập các giá trị cũ. – Eevee

5

Tin vui! Điều này là hoàn toàn không thể. Tên thẻ HTML là baked right into libxml2.

lxml.html.html5parser chứa một vài lỗi nghiêm trọng mà bản sửa lỗi chưa đưa ra bản phát hành.

Nhưng heck, hãy sửa chúng cục bộ và xem điều gì xảy ra.

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>'), encoding=unicode) 
u'<html:p xmlns:html="http://www.w3.org/1999/xhtml">hello<html:wbr></html:wbr>world!</html:p>' 

Rất gần, nhưng cho đến nay. Cấu trúc là chính xác, ít nhất.

hơn Một thử:

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>', parser=lxml.html.html5parser.HTMLParser(namespaceHTMLElements=False)), encoding=unicode) 
u'<p>hello<wbr></wbr>world!</p>' 

Welp.

Nó không phải là sai, ít nhất.

Tôi nghĩ rằng tôi có thể gửi một số lỗi chống lại lxml và libxml2.

1

Để khắc phục nhanh, tại sao không sử dụng phương pháp chuỗi replace để xóa thẻ đóng?

>>> t = 'Thisisa<wbr></wbr>test' 
>>> t.replace('</wbr>', '') 
'Thisisa<wbr>test'