Python - XML Processing

XML là một ngôn ngữ di động, mã nguồn mở cho phép lập trình viên phát triển các ứng dụng có thể được đọc bởi các ứng dụng khác, bất kể hệ điều hành và/hoặc ngôn ngữ phát triển.

What is XML?

Ngôn ngữ Đánh dấu Mở rộng (XML) là một ngôn ngữ đánh dấu tương tự như HTML hoặc SGML. Điều này được Tổ chức W3C (World Wide Web Consortium) khuyến nghị và có sẵn như một tiêu chuẩn mở.

XML rất hữu ích để theo dõi một lượng dữ liệu nhỏ đến trung bình mà không cần một hệ thống cơ sở dữ liệu dựa trên SQL.

XML Parser Architectures and APIs.

Thư viện chuẩn của Python cung cấp một tập hợp các giao diện tối thiểu nhưng hữu ích để làm việc với XML. Tất cả các tiểu mô-đun để xử lý XML đều có sẵn trong gói xml.

  • xml.etree.ElementTree − API ElementTree, một trình xử lý XML đơn giản và nhẹ

  • xml.dom − định nghĩa API DOM.

  • xml.dom.minidom − một triển khai DOM tối thiểu.

  • xml.dom.pulldom − hỗ trợ xây dựng các cây DOM phần.

  • xml.sax − Các lớp cơ sở SAX2 và các hàm tiện ích.

  • xml.parsers.expat − liên kết phân tích cú pháp Expat.

Hai API cơ bản và được sử dụng rộng rãi nhất để xử lý dữ liệu XML là các giao diện SAX và DOM.

  • Simple API for XML (SAX) − Ở đây, bạn đăng ký các callback cho các sự kiện quan tâm và sau đó để trình phân tích tiếp tục qua tài liệu. Điều này hữu ích khi tài liệu của bạn lớn hoặc bạn có giới hạn về bộ nhớ, nó phân tích tệp khi đọc từ đĩa và toàn bộ tệp không bao giờ được lưu trữ trong bộ nhớ.

  • Document Object Model (DOM) − Đây là một khuyến nghị của Tổ chức W3C, trong đó toàn bộ tệp được đọc vào bộ nhớ và lưu trữ dưới dạng cấu trúc phân cấp (dựa trên cây) để đại diện cho tất cả các đặc điểm của một tài liệu XML.

SAX rõ ràng không thể xử lý thông tin nhanh như DOM khi làm việc với các tệp lớn. Mặt khác, việc chỉ sử dụng DOM có thể tiêu tốn tài nguyên của bạn, đặc biệt nếu được sử dụng trên nhiều tệp nhỏ.

SAX là chế độ chỉ đọc, trong khi DOM cho phép thay đổi tệp XML. Vì hai API khác nhau này thực sự bổ sung cho nhau, nên không có lý do gì bạn không thể sử dụng cả hai cho các dự án lớn.

Đối với tất cả các ví dụ mã XML của chúng tôi, hãy sử dụng một tệp XML đơn giản movies.xml làm đầu vào −

<collection shelf="New Arrivals">
<movie title="Enemy Behind">
   <type>War, Thriller</type>
   <format>DVD</format>
   <year>2003</year>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
   <type>Anime, Science Fiction</type>
   <format>DVD</format>
   <year>1989</year>
   <rating>R</rating>
   <stars>8</stars>
   <description>A schientific fiction</description>
</movie>
   <movie title="Trigun">
   <type>Anime, Action</type>
   <format>DVD</format>
   <episodes>4</episodes>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Vash the Stampede!</description>
</movie>
   <movie title="Ishtar">
   <type>Comedy</type>
   <format>VHS</format>
   <rating>PG</rating>
   <stars>2</stars>
   <description>Viewable boredom</description>
</movie>
</collection>

Parsing XML with SAX APIs

SAX là một giao diện chuẩn cho việc phân tích XML dựa trên sự kiện. Việc phân tích XML bằng SAX thường yêu cầu bạn tạo ra ContentHandler của riêng mình bằng cách kế thừa từ xml.sax.ContentHandler.

ContentHandler của bạn xử lý các thẻ và thuộc tính cụ thể của hương vị XML của bạn. Một đối tượng ContentHandler cung cấp các phương thức để xử lý các sự kiện phân tích khác nhau. Bộ phân tích của nó gọi các phương thức ContentHandler khi nó phân tích tệp XML.

Các phương thức startDocument và endDocument được gọi ở đầu và cuối của tệp XML. Phương thức characters(text) nhận dữ liệu ký tự của tệp XML thông qua tham số text.

ContentHandler được gọi tại đầu và cuối của mỗi phần tử. Nếu trình phân tích cú pháp không ở chế độ không gian tên, các phương thức startElement(tag, attributes) và endElement(tag) sẽ được gọi; ngược lại, các phương thức tương ứng startElementNS và endElementNS sẽ được gọi. Ở đây, tag là thẻ phần tử, và attributes là một đối tượng Attributes.

Dưới đây là một số phương thức quan trọng khác cần hiểu trước khi tiếp tục −

The make_parser Method

Phương thức sau đây tạo ra một đối tượng phân tích cú pháp mới và trả về nó. Đối tượng phân tích cú pháp được tạo ra sẽ thuộc loại phân tích cú pháp đầu tiên mà hệ thống tìm thấy.

xml.sax.make_parser( [parser_list] )

Dưới đây là chi tiết của các tham số −

  • parser_list − Tham số tùy chọn bao gồm một danh sách các bộ phân tích cú pháp (parsers) để sử dụng, tất cả phải triển khai phương thức make_parser.

The parse Method

Phương thức sau tạo một trình phân tích SAX và sử dụng nó để phân tích một tài liệu.

xml.sax.parse( xmlfile, contenthandler[, errorhandler])

Dưới đây là chi tiết của các tham số −

  • xmlfile − Đây là tên của tệp XML để đọc từ đó.

  • contenthandler − Đây phải là một đối tượng ContentHandler.

  • errorhandler − Nếu được chỉ định, errorhandler phải là một đối tượng SAX ErrorHandler.

The parseString Method

Có một phương pháp nữa để tạo một trình phân tích SAX và phân tích chuỗi XML đã chỉ định.

xml.sax.parseString(xmlstring, contenthandler[, errorhandler])

Dưới đây là chi tiết của các tham số −

  • xmlstring − Đây là tên của chuỗi XML để đọc từ.

  • contenthandler − Đây phải là một đối tượng ContentHandler.

  • errorhandler − Nếu được chỉ định, errorhandler phải là một đối tượng SAX ErrorHandler.

Example

import xml.sax
class MovieHandler( xml.sax.ContentHandler ):
   def __init__(self):
      self.CurrentData = ""
      self.type = ""
      self.format = ""
      self.year = ""
      self.rating = ""
      self.stars = ""
      self.description = ""

   # Call when an element starts
   def startElement(self, tag, attributes):
      self.CurrentData = tag
      if tag == "movie":
         print ("*****Movie*****")
         title = attributes["title"]
         print ("Title:", title)

   # Call when an elements ends
   def endElement(self, tag):
      if self.CurrentData == "type":
         print ("Type:", self.type)
      elif self.CurrentData == "format":
         print ("Format:", self.format)
      elif self.CurrentData == "year":
         print ("Year:", self.year)
      elif self.CurrentData == "rating":
         print ("Rating:", self.rating)
      elif self.CurrentData == "stars":
         print ("Stars:", self.stars)
      elif self.CurrentData == "description":
         print ("Description:", self.description)
      self.CurrentData = ""

   # Call when a character is read
   def characters(self, content):
      if self.CurrentData == "type":
         self.type = content
      elif self.CurrentData == "format":
         self.format = content
      elif self.CurrentData == "year":
         self.year = content
      elif self.CurrentData == "rating":
         self.rating = content
      elif self.CurrentData == "stars":
         self.stars = content
      elif self.CurrentData == "description":
         self.description = content

if ( __name__ == "__main__"):

   # create an XMLReader
   parser = xml.sax.make_parser()
   
   # turn off namepsaces
   parser.setFeature(xml.sax.handler.feature_namespaces, 0)
   
   # override the default ContextHandler
   Handler = MovieHandler()
   parser.setContentHandler( Handler )
   
   parser.parse("movies.xml")

Điều này sẽ tạo ra kết quả sau −

*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Year: 2003
Rating: PG
Stars: 10
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Year: 1989
Rating: R
Stars: 8
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Stars: 10
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Stars: 2
Description: Viewable boredom

Để biết chi tiết đầy đủ về tài liệu API SAX, vui lòng tham khảo Python SAX APIs .

Parsing XML with DOM APIs

Mô hình Đối tượng Tài liệu ("DOM") là một API đa ngôn ngữ từ Tổ chức W3C để truy cập và sửa đổi các tài liệu XML.

DOM cực kỳ hữu ích cho các ứng dụng truy cập ngẫu nhiên. SAX chỉ cho phép bạn xem một phần của tài liệu tại một thời điểm. Nếu bạn đang xem một phần tử SAX, bạn sẽ không có quyền truy cập vào phần tử khác.

Dưới đây là cách dễ nhất để tải một tài liệu XML nhanh chóng và tạo một đối tượng minidom bằng cách sử dụng module xml.dom. Đối tượng minidom cung cấp một phương thức phân tích cú pháp đơn giản giúp nhanh chóng tạo ra một cây DOM từ tệp XML.

Câu mẫu gọi hàm parse( file [,parser] ) của đối tượng minidom để phân tích tệp XML, được chỉ định bởi file, thành một đối tượng cây DOM.

from xml.dom.minidom import parse
import xml.dom.minidom

# Open XML document using minidom parser
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
   print ("Root element : %s" % collection.getAttribute("shelf"))

# Get all the movies in the collection
movies = collection.getElementsByTagName("movie")

# Print detail of each movie.
for movie in movies:
   print ("*****Movie*****")
   if movie.hasAttribute("title"):
      print ("Title: %s" % movie.getAttribute("title"))

   type = movie.getElementsByTagName('type')[0]
   print ("Type: %s" % type.childNodes[0].data)
   format = movie.getElementsByTagName('format')[0]
   print ("Format: %s" % format.childNodes[0].data)
   rating = movie.getElementsByTagName('rating')[0]
   print ("Rating: %s" % rating.childNodes[0].data)
   description = movie.getElementsByTagName('description')[0]
   print ("Description: %s" % description.childNodes[0].data)

Điều này sẽ tạo ra output

Root element : New Arrivals
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Rating: PG
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Rating: R
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Description: Viewable boredom

Để biết chi tiết đầy đủ về tài liệu API DOM, vui lòng tham khảo tiêu chuẩn Python DOM APIs .

ElementTree XML API

Gói xml có một mô-đun ElementTree. Đây là một API xử lý XML đơn giản và nhẹ.

XML là một định dạng dữ liệu theo cấu trúc phân cấp giống như cây. 'ElementTree' trong mô-đun này coi toàn bộ tài liệu XML như một cây. Lớp 'Element' đại diện cho một nút đơn trong cây này. Các thao tác đọc và ghi trên các tệp XML được thực hiện ở cấp độ ElementTree. Các tương tác với một phần tử XML đơn và các phần tử con của nó được thực hiện ở cấp độ Element.

Create an XML File

Cây là một cấu trúc phân cấp của các phần tử bắt đầu với nút gốc, tiếp theo là các phần tử khác. Mỗi phần tử được tạo ra bằng cách sử dụng hàm Element() của mô-đun này.

import xml.etree.ElementTree as et
e=et.Element('name')

Mỗi phần tử được đặc trưng bởi một thẻ và thuộc tính attrib, thuộc tính này là một đối tượng dict. Đối với phần tử bắt đầu của cây, attrib là một từ điển rỗng.

>>> root=xml.Element('employees')
>>> root.tag
'employees'
>>> root.attrib
{}

Bạn bây giờ có thể thiết lập một hoặc nhiều phần tử con để được thêm vào dưới phần tử gốc. Mỗi phần tử con có thể có một hoặc nhiều phần tử con phụ. Thêm chúng bằng cách sử dụng hàm SubElement() và định nghĩa thuộc tính văn bản của nó.

child=xml.Element("employee")
nm = xml.SubElement(child, "name")
nm.text = student.get('name')
age = xml.SubElement(child, "salary")
age.text = str(student.get('salary'))

Mỗi đứa trẻ được thêm vào gốc bằng hàm append() như sau −

root.append(child)

Sau khi thêm số lượng phần tử con cần thiết, hãy xây dựng một đối tượng cây bằng cách sử dụng hàm elementTree().

tree = et.ElementTree(root)

Toàn bộ cấu trúc cây được ghi vào một tệp nhị phân bởi hàm write() của đối tượng cây.

f=open('employees.xml', "wb")
tree.write(f)

Example

Trong ví dụ này, một cây được xây dựng từ một danh sách các mục từ điển. Mỗi mục từ điển chứa các cặp khóa-giá trị mô tả cấu trúc dữ liệu của một sinh viên. Cây được xây dựng sẽ được ghi vào 'myfile.xml'.

import xml.etree.ElementTree as et
employees=[{'name':'aaa','age':21,'sal':5000},{'name':xyz,'age':22,'sal':6000}]
root = et.Element("employees")
for employee in employees:
   child=xml.Element("employee")
   root.append(child)
   nm = xml.SubElement(child, "name")
   nm.text = student.get('name')
   age = xml.SubElement(child, "age")
   age.text = str(student.get('age'))
   sal=xml.SubElement(child, "sal")
   sal.text=str(student.get('sal'))
tree = et.ElementTree(root)
with open('employees.xml', "wb") as fh:
   tree.write(fh)

Tệp 'myfile.xml' được lưu trữ trong thư mục làm việc hiện tại.

<employees><employee><name>aaa</name><age>21</age><sal>5000</sal></employee><employee><name>xyz</name><age>22</age><sal>60</sal></employee></employee>

Parse an XML File

Bây giờ, chúng ta hãy đọc lại 'myfile.xml' được tạo ra trong ví dụ trên. Để làm điều này, các hàm sau trong mô-đun ElementTree sẽ được sử dụng −

ElementTree() − Hàm này được nạp chồng để đọc cấu trúc phân cấp của các phần tử vào các đối tượng cây.

tree = et.ElementTree(file='students.xml')

getroot() − Hàm này trả về phần tử gốc của cây.

root = tree.getroot()

Bạn có thể lấy danh sách các phần tử con nằm một cấp dưới của một phần tử.

children = list(root)

Trong ví dụ sau, các phần tử và tiểu phần tử của 'myfile.xml' được phân tích thành một danh sách các mục từ điển.

Example

import xml.etree.ElementTree as et
tree = et.ElementTree(file='employees.xml')
root = tree.getroot()
employees=[]
   children = list(root)
for child in children:
   employee={}
   pairs = list(child)
   for pair in pairs:
      employee[pair.tag]=pair.text
   employees.append(employee)
print (employees)

Nó sẽ tạo ra output

[{'name': 'aaa', 'age': '21', 'sal': '5000'}, {'name': 'xyz', 'age':'22', 'sal': '6000'}]

Modify an XML file

Chúng ta sẽ sử dụng hàm iter() của Element. Nó tạo ra một bộ lặp cây cho thẻ đã cho với phần tử hiện tại làm gốc. Bộ lặp sẽ lặp qua phần tử này và tất cả các phần tử bên dưới nó, theo thứ tự tài liệu (theo chiều sâu).

Hãy xây dựng bộ lặp cho tất cả các phần tử con 'marks' và tăng giá trị văn bản của mỗi thẻ sal lên 100.

import xml.etree.ElementTree as et
tree = et.ElementTree(file='students.xml')
root = tree.getroot()
for x in root.iter('sal'):
   s=int (x.text)
   s=s+100
   x.text=str(s)
with open("employees.xml", "wb") as fh:
   tree.write(fh)

Tập tin 'employees.xml' của chúng tôi sẽ được chỉnh sửa tương ứng. Chúng tôi cũng có thể sử dụng set() để cập nhật giá trị của một khóa nhất định.

x.set(marks, str(mark))