Hướng Dẫn Sử Dụng lxml trong Python - tu vi hang ngay 12 con giap
Trong những ngày gần đây, vì cần xử lý các tệp XML, tôi đã dành thời gian nghiên cứu thư viện lxml và muốn chia sẻ một số kết quả. Bài viết này sẽ giải đáp ba câu hỏi chính mà tôi thường gặp khi làm việc với XML.
Mọi đoạn mã được trình bày đều đã được kiểm tra trên Python 3.5. Trước khi bắt đầu, hãy cùng nhau nhập module lxml.etree – nơi chứa hầu hết các chức năng xử lý XML:
1>>> from lxml import etree
Lớp Element
Phần này sẽ trả lời câu hỏi thứ ba về cách xử lý XML. Lớp Element
là thành phần cốt lõi khi làm việc với XML. Một đối tượng Element
có thể được hiểu đơn giản như một nút (node) trong cây XML. Phần lớn các thao tác liên quan đến XML đều xoay quanh lớp này. Nội dung sẽ bao gồm ba chủ đề: thao tác với nút, thao tác với thuộc tính của nút, và thao tác với văn bản bên trong nút.
Thao Tác Với Nút
1. Tạo đối tượng Element
:
1>>> root = etree.Element('root')
2>>> print(root)
3<Element root at 0x2da0708>
2. Lấy tên của nút:
1>>> print(root.tag)
2root
3. Xuất nội dung XML:
1>>> print(etree.tostring(root))
2b'<root/>'
4. Thêm nút con:
1>>> child1 = etree.SubElement(root, 'child1')
2>>> child2 = etree.SubElement(root, 'child2')
3>>> child3 = etree.SubElement(root, 'child3')
5. Xóa nút con:
1>>> root.remove(child1) # Xóa nút con cụ thể
2>>> print(etree.tostring(root))
3b'<root><child2/><child3/></root>'
4>>> root.clear() # Xóa tất cả nút con
5>>> print(etree.tostring(root))
6b'<root/>'
6. Các thao tác kiểu danh sách: Các nút con có thể được truy cập giống như một danh sách:
1>>> child = root[0] # Truy cập bằng chỉ mục
2>>> print(child.tag)
3child1
4>>> print(len(root)) # Số lượng nút con
53
6>>> root.index(child2) # Lấy vị trí
71
8>>> for child in root: # Duyệt qua từng nút
9... print(child.tag)
10child1
11child2
12child3
13>>> root.insert(0, etree.Element('child0')) # Chèn vào vị trí
14>>> start = root[:1] # Cắt danh sách
15>>> end = root[-1:]
16>>> print(start[0].tag)
17child0
18>>> print(end[0].tag)
19child3
20>>> root.append( etree.Element('child4') ) # Thêm vào cuối danh sách
21>>> print(etree.tostring(root))
22b'<root><child0/><child1/><child2/><child3/><child4/></root>'
Hai phương thức remove
và clear
cũng tương tự như cách hoạt động của danh sách.
7. Lấy nút cha:
1>>> print(child1.getparent().tag)
2root
Thao Tác Với Thuộc Tính
Thuộc tính của nút được lưu trữ dưới dạng cặp key-value, giống như từ điển. 1. Tạo thuộc tính:
1>>> root = etree.Element('root', interesting='totally')
2>>> print(etree.tostring(root))
3b'<root interesting="totally"/>'
Bạn cũng có thể sử dụng phương thức set
để thêm thuộc tính cho nút hiện tại:
1>>> root.set('hello', 'Huhu')
2>>> print(etree.tostring(root))
3b'<root interesting="totally" hello="Huhu"/>'
2. Lấy thuộc tính:
1# Phương thức get để lấy giá trị của một thuộc tính cụ thể
2>>> print(root.get('interesting'))
3totally
4# Phương thức keys để lấy danh sách tên thuộc tính
5>>> sorted(root.keys())
6['hello', 'interesting']
7# Phương thức items để lấy tất cả cặp key-value
8>>> for name, value in sorted(root.items()):
9... print('%s = %r' % (name, value))
10hello = 'Huhu'
11interesting = 'totally'
Bạn cũng có thể sử dụng thuộc tính attrib
để lấy toàn bộ các thuộc tính dưới dạng từ điển:
1>>> attributes = root.attrib
2>>> print(attributes)
3{'interesting': 'totally', 'hello': 'Huhu'}
4>>> attributes['good'] = 'Bye' # Sửa đổi từ điển ảnh hưởng trực tiếp đến nút
5>>> print(root.get('good'))
6Bye
Thao Tác Với Văn Bản
Sau khi đã làm quen với các nút và thuộc tính, bây giờ chúng ta sẽ tìm hiểu cách xử lý văn bản bên trong các thẻ XML. Có hai cách chính để truy cập văn bản: thông qua thuộc tính text
và tail
, hoặc thông qua cú pháp XPath.
1. Thuộc tính text
và tail
:
1>>> root = etree.Element('root')
2>>> root.text = 'Xin chào, thế giới!'
3>>> print(root.text)
4Xin chào, thế giới!
5>>> print(etree.tostring(root))
6b'<root>Xin chào, thế giới!</root>'
XML thường có các cặp thẻ mở và đóng, nhưng đôi khi bạn sẽ gặp các thẻ đơn như <br/>
trong HTML:
1<html><body>Chữ<b></b>Đuôi</body></html>
Lớp Element
hỗ trợ thuộc tính tail
để xử lý văn bản sau các thẻ đơn:
1>>> html = etree.Element('html')
2>>> body = etree.SubElement(html, 'body')
3>>> body.text = 'Chữ'
4>>> print(etree.tostring(html))
5b'<html><body>Chữ</body></html>'
6>>> br = etree.SubElement(body, 'b')
7>>> print(etree.tostring(html))
8b'<html><body>Chữ<b/></body></html>'
9# tail chỉ thêm văn bản sau thẻ
10>>> br.tail = 'Đuôi'
11>>> print(etree.tostring(br))
12b'<b/>Đuôi'
13>>> print(etree.tostring(html))
14b'<html><body>Chữ<b/>Đuôi</body></html>'
15# tostring với tham số method lọc các thẻ đơn và xuất toàn bộ văn bản
16>>> print(etree.tostring(html, method='text'))
17b'ChữĐuôi'
2. Cách dùng XPath:
1# Cách một: Lọc các thẻ đơn và trả về văn bản
2>>> print(html.xpath('string()'))
3ChữĐuôi
4# Cách hai: Trả về danh sách với các thẻ đơn làm ranh giới
5>>> print(html.xpath('//text()'))
6['Chữ', 'Đuôi']
Danh sách thu được từ cách hai sẽ chứa thông tin về nút và loại văn bản:
1>>> texts = html.xpath('//text()')
2>>> print(texts[0])
3Chữ
4# Nút sở hữu
5>>> parent = texts[0].getparent()
6>>> print(parent.tag)
7body
8>>> print(texts[1], texts[1].getparent().tag)
9Đuôi b
10# Kiểu văn bản: Là văn bản thông thường hay đuôi
11>>> print(texts[0].is_text)
12True
13>>> print(texts[1].is_text)
14False
15>>> print(texts[1].is_tail)
16True
Phân Tích Và Xuất File
Phần này sẽ trả lời câu hỏi thứ nhất về cách đọc và ghi file XML. Chúng ta sẽ tìm hiểu cách chuyển đổi giữa file XML và đối tượng Element
.
1. Đọc file XML:
1>>> xml_data = '<root>data</root>'
2# Phương thức fromstring
3>>> root1 = etree.fromstring(xml_data)
4>>> print(root1.tag)
5root
6>>> print(etree.tostring(root1))
7b'<root>data</root>'
8# Phương thức XML, tương tự như fromstring
9>>> root2 = etree.XML(xml_data)
10>>> print(root2.tag)
11root
12>>> print(etree.tostring(root2))
13b'<root>data</root>'
14# Phương thức HTML, tự động bổ sung các thẻ <html> và <body> nếu thiếu
15>>> root3 = etree.HTML(xml_data)
16>>> print(root3.tag)
17html
18>>> print(etree.tostring(root3))
19b'<html><body><root>data</root></body></html>'
2. Xuất file XML:
1>>> root = etree.XML('<root><a><b/></a></root>')
2>>> print(etree.tostring(root))
3b'<root><a><b/></a></root>'
4# Khai báo XML
5>>> print(etree.tostring(root, xml_declaration=True))
6b"<?xml version='1.0' encoding='ASCII'?>\n<root><a><b/></a></root>"
7# Chỉ định mã hóa
8>>> print(etree.tostring(root, encoding='iso-8859-1'))
9b"<?xml version='1.0' encoding='iso-8859-1'?>\n<root><a><b/></a></root>"
ElementPath
Phần này sẽ trả lời câu hỏi thứ hai về cách tìm kiếm và định vị các phần tử trong cây XML. Để làm điều đó, chúng ta sẽ sử dụng ElementPath
, một công cụ tương tự như XPath trong XML.
1>>> root = etree.XML("<root><a x='123'>Văn bản<b/><c/><b/></a></root>")
2# Tìm thẻ b đầu tiên
3>>> print(root.find('b'))
4None
5>>> print(root.find('a').tag)
6a
7# Tìm tất cả các thẻ b, trả về danh sách các đối tượng Element
8>>> [ b.tag for b in root.findall('.//b') ]
9['b', 'b']
10# Tìm theo thuộc tính
11>>> print(root.findall('.//a[@x]')[0].tag)
12a
13>>> print(root.findall('.//a[@y]'))
14[]
Tài Liệu
- Tài liệu chính thức của lxml:
- Ngữ pháp XPath: