2010-07-19 34 views
5

Tôi đang làm việc trên một ứng dụng, và công việc của tôi chỉ là phát triển một giao diện Python mẫu cho ứng dụng. Ứng dụng có thể cung cấp tài liệu dựa trên XML, tôi có thể lấy tài liệu thông qua phương thức HTTP Get, nhưng vấn đề là tài liệu dựa trên XML là vô tận có nghĩa là sẽ không có phần tử kết thúc. Tôi biết rằng tài liệu nên được xử lý bởi SAX, nhưng làm thế nào để đối phó với vấn đề vô tận? Bất kỳ ý tưởng, mã mẫu?python xử lý XML vô tận

+1

Âm thanh như một cơ hội tốt để khám phá máy phát điện Python. –

Trả lời

2

Nếu tài liệu không bao giờ nhận được thẻ đóng cho một phần tử trong tài liệu, thì đó không phải là XML được định dạng chính xác, nó sẽ phát tàn phá với bất kỳ trình phân tích cú pháp XML nào.

Điều đó nói rằng, bằng cách sử dụng Python SAX2 API có vẻ là cách tiếp cận tốt nhất, nhưng bạn sẽ phải xác định ngoại lệ nào sẽ được ném bởi thẻ đóng bị thiếu, nắm bắt và xử lý nó.

Added

Giả sử rằng bạn đang nhận được một tài liệu XML như thế này:

<? xml version="1.0" ?> 
<foo> 
    <bar>...</bar> 
    <bar>...</bar> 
    <bar>...</bar> 
    <bar>...</bar> 
    ... 

Và bạn không bao giờ nhận được một kết thúc </foo>. Trong trường hợp này, trình phân tích cú pháp SAX phản ứng với các yếu tố bar sẽ phát hành luồng sự kiện cho startElement(bar)endElement(bar). Có lẽ bạn sẽ thu thập tất cả dữ liệu giữa đầu và cuối, sau đó xử lý tất cả dữ liệu tại một lần khi bạn thấy sự kiện kết thúc.

Cách duy nhất để dừng vòng lặp này là thông qua hành động bên ngoài: xác định trước số lượng các yếu tố bar để xử lý hoặc xác định trước khoảng thời gian bạn muốn dành cho việc nhận các sự kiện bar. Chạy trình phân tích cú pháp SAX trong một chuỗi và sau đó tiêu diệt chuỗi khi bạn đạt đến giới hạn của mình. Bạn sẽ muốn có quá trình ngủ chính của bạn trong khi chờ đợi trên sợi sax-parser để kết thúc.

+0

Tôi không mong đợi một ngoại lệ: điểm là luồng XML không có EOF, do đó không có điều kiện lỗi. –

3

Hãy nhìn vào các mô-đun xmlstream trong jabberpy (cũng có sẵn từ twisted):

xmlstream.py cung cấp chức năng đơn giản để thực hiện dựa trên giao thức mạng dòng XML. Nó được sử dụng làm cơ sở cho jabber.py.

xmlstream.py quản lý kết nối mạng và phân tích cú pháp xml luồng. Khi một 'phần tử giao thức' hoàn chỉnh (có nghĩa là một con số hoàn chỉnh của số xmlstreams root) được phân tích cú pháp phương thức dipatch được gọi với một thể hiện 'Node' của cấu trúc này. Lớp Nút là một DOM XML rất đơn giản như lớp cho việc biên tập các tài liệu XML hoặc 'các phần tử giao thức' trong trường hợp này cho lớp .

0

Tôi cho rằng XML của bạn về cơ bản là danh sách các phần tử XML giống nhau được tập hợp trong một phần tử vùng chứa. Một cái gì đó như

<items> 
    <item> 
    <!-- content here --> 
    </item> 
    <item> 
    <!-- content here --> 
    </item> 
    <item> 
    <!-- content here --> 
    </item> 
</items> 

Trong SAX khi phân tích cú pháp của bạn được và sự kiện kết thúc, bạn có thể phân tích các mục hoàn thành, hãy bỏ chồng, và vượt qua các mục trên để bất cứ điều gì mã khác nên được xử lý mặt hàng phân tích cú pháp.

def process(item) : 
    # App logic goes here 

class ItemsHandler(xml.sax.handler.ContentHandler) : 
    # Omitting __init__, startElement, and characters methods 
    # to store data on a stack during processing 

    def endElement(self, name) : 
    if name == "item" : 
     # create item from stored data on stack 
     parsed_item = self.parse_item_from_stack() 
     process(parsed_item) 

Nếu logic ứng dụng đủ phức tạp, bạn sẽ muốn phân tích cú pháp SAX trong một chuỗi riêng biệt để bạn không bỏ lỡ các sự kiện.

0

Nếu tài liệu là vô tận tại sao không thêm thẻ kết thúc (của phần tử chính) theo cách thủ công trước khi mở nó trong trình phân tích cú pháp? Tôi không biết Python nhưng tại sao không thêm </endtag> vào chuỗi?

+0

Đơn giản: vì không có phần cuối của tài liệu đó. Vì vậy, bạn không thể "thêm" 'vào cuối". – arilou

0

Tôi không thể cung cấp giải pháp bằng Python ngay lập tức, nhưng sẽ cung cấp cho bạn gợi ý.

Loại phân tích cú pháp XML đó được xử lý bởi StAX trình phân tích cú pháp. Vấn đề ở đây là một trình phân tích cú pháp SAX đẩy các sự kiện, nhưng giao diện chứng minh StAX để kéo các sự kiện. StAX được sử dụng chủ yếu cho phân tích cú pháp XML một phần (chỉ phân tích cú pháp tiêu đề từ một thông điệp SOAP), và điều này có vẻ là trường hợp của bạn.

Tôi chưa thấy một trình phân tích cú pháp giống như StAX trong thư viện chuẩn Python, nhưng chắc chắn phải có một.

UPD: lxml (dưới dạng trình bao bọc tp libxml2) dường như có similar functinality.

6

Đây là những gì tôi sử dụng cho phân tích một dòng xml vô tận mà tôi nhận được từ một máy tính từ xa (trong trường hợp của tôi, tôi kết nối qua một ổ cắm và sử dụng socket.makefile ('r') để tạo ra các đối tượng tập tin)

19.12.2. IncrementalParser Objects

parser = xml.sax.make_parser(['xml.sax.IncrementalParser']) 
handler = FooHandler() 
parser.setContentHandler(handler) 

data = sockfile.readline() 
while (len(data) != 0): 
    parser.feed(data) 
    data = sockfilefile.readline() 
+1

Trên thực tế, không có biểu tượng nào như 'xml.sax.IncrementalParser' và' make_parser' mong đợi một danh sách các mô đun có hàm 'create_parser'. Có 'xml.sax.xmlreader.IncrementalParser', nhưng nó không thực hiện' feed', chỉ là một giao diện. May mắn là mô-đun phân tích cú pháp mặc định, 'xml.sax.expatreader', mà' make_parser' cố tải sau khi nó không tải được các mô-đun do người dùng cung cấp, thực hiện 'xml.sax.xmlreader.IncrementalParser'. Vì vậy, nó đủ để gọi 'make_parse' mà không có một đối số. – saaj

0

Bạn có thể sử dụng chức năng iterparse từ xml.etree.ElementTree (hoặc cElementTree cho tốc độ) trong stdlib. (Bạn cũng có thể sử dụng lxml)

Bí quyết được mô tả ở đây: http://effbot.org/zone/element-iterparse.htm#incremental-parsing

Ví dụ mô tả chính xác những gì bạn cần. Nó không đề cập đến bất cứ điều gì về các tập tin vô tận, nhưng nó sẽ hoạt động. (nó sẽ tiếp tục đi). Quan trọng nhất: đừng quên xóa phần tử gốc.

Dễ dàng và có sẵn trong phần cứng ;-)

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