2011-08-30 23 views
17

Tôi có một tập hợp các tệp XML siêu đơn giản để phân tích cú pháp ... nhưng ... chúng sử dụng các thực thể được xác định tùy chỉnh. Tôi không cần phải vẽ bản đồ cho các nhân vật, nhưng tôi muốn phân tích và hành động theo từng nhân vật. Ví dụ:Hỗ trợ Python ElementTree để phân tích các thực thể XML không xác định?

<Style name="admin-5678"> 
    <Rule> 
     <Filter>[admin_level]='5'</Filter> 
     &maxscale_zoom11; 
    </Rule> 
</Style> 

Có một gợi ý trêu ngươi tại http://effbot.org/elementtree/elementtree-xmlparser.htm rằng XMLParser đã hạn chế hỗ trợ tổ chức nào, nhưng tôi không thể tìm ra các phương pháp đã đề cập, tất cả mọi thứ cho lỗi:

#!/usr/bin/python 
    ## 
    ## Where's the entity support as documented at: 
    ## http://effbot.org/elementtree/elementtree-xmlparser.htm 
    ## In Python 2.7.1+ ? 
    ## 
    from pprint  import pprint 
    from xml.etree import ElementTree 
    from cStringIO import StringIO 

    parser = ElementTree.ElementTree() 
    #parser.entity["maxscale_zoom11"] = unichr(160) 
    testf = StringIO('<foo>&maxscale_zoom11;</foo>') 
    tree = parser.parse(testf) 
    #tree = parser.parse(testf,"XMLParser") 
    for node in tree.iter('foo'): 
     print node.text 

nào tùy thuộc vào cách bạn điều chỉnh các ý kiến ​​đưa ra:

xml.etree.ElementTree.ParseError: undefined entity: line 1, column 5 

hoặc

AttributeError: 'ElementTree' object has no attribute 'entity' 

hoặc

AttributeError: 'str' object has no attribute 'feed'   

Đối với những người tò mò XML là từ 's mapnik dự án OpenStreetMap.

+0

Có thể liên quan câu hỏi: http://stackoverflow.com/questions/2524299/entity-references-and-lxml – unutbu

+0

Không liên quan, bởi vì trong trường hợp đó, thực thể được thực sự xác định. Xóa định nghĩa đối tượng và bạn quay lại câu hỏi của tôi. – Bryce

+0

fyi - ai đó có thể muốn sửa/usr/bin/python thành/usr/bin/env python vì dòng shebang là sai đối với hầu hết các hệ thống. –

Trả lời

11

Tôi không chắc đây có phải là lỗi trong ElementTree hay không, nhưng bạn cần gọi UseForeignDTD (True) trên trình phân tích cú pháp người nước ngoài để hoạt động theo cách mà nó đã làm trong quá khứ.

Đó là một chút hacky, nhưng bạn có thể làm điều này bằng cách tạo trường hợp của riêng bạn của ElementTree.Parser, gọi phương thức trên trường hợp của nó là xml.parsers.expat và sau đó chuyển nó tới ElementTree.parse():

from xml.etree import ElementTree 
from cStringIO import StringIO 


testf = StringIO('<foo>&moo_1;</foo>') 

parser = ElementTree.XMLParser() 
parser.parser.UseForeignDTD(True) 
parser.entity['moo_1'] = 'MOOOOO' 

etree = ElementTree.ElementTree() 

tree = etree.parse(testf, parser=parser) 

for node in tree.iter('foo'): 
    print node.text 

này kết quả đầu ra "MOOOOO"

Hoặc sử dụng một giao diện lập bản đồ:

from xml.etree import ElementTree 
from cStringIO import StringIO 

class AllEntities: 
    def __getitem__(self, key): 
     #key is your entity, you can do whatever you want with it here 
     return key 

testf = StringIO('<foo>&moo_1;</foo>') 

parser = ElementTree.XMLParser() 
parser.parser.UseForeignDTD(True) 
parser.entity = AllEntities() 

etree = ElementTree.ElementTree() 

tree = etree.parse(testf, parser=parser) 

for node in tree.iter('foo'): 
    print node.text 

này kết quả đầu ra "moo_1"

Một sửa chữa phức tạp hơn sẽ là phân lớp ElementTree.XMLParser và sửa chữa nó ở đó.

+0

Một chút icky như bạn nói, nhưng cảm ơn. Có cách nào để tránh phải xác định trước các thực thể (ví dụ: & moo_2). – Bryce

+0

@Bryce: được xác định trước là điểm của các thực thể, phải không? Tuy nhiên: bạn có thể đặt 'parser.entity' thành đối tượng giống từ điển của riêng bạn. Như một ví dụ đơn giản, bạn có thể thực hiện 'parser.entity = collections.defaultdict (str) 'để có tất cả các thực thể không xác định được thay thế bằng một chuỗi rỗng. – Steven

+0

Để theo dõi nhận xét của Steven, bạn cũng có thể triển khai giao diện bản đồ và thực hiện bất cứ điều gì bạn muốn với các phím. Tôi đã chỉnh sửa câu trả lời của mình để hiển thị một ví dụ đơn giản về điều đó. – cnelson

3

Như @cnelson đã nêu trong nhận xét, giải pháp đã chọn ở đây sẽ không hoạt động trong Python 3.

Cuối cùng tôi đã làm việc. Được trích dẫn từ số Q&A này.

Lấy cảm hứng từ this post, chúng tôi chỉ có thể thêm một số định nghĩa XML vào nội dung HTML thô đến, và sau đó ElementTree sẽ hoạt động ra khỏi hộp.

Điều này phù hợp với cả Python 2.6, 2.7, 3.3, 3.4.

import xml.etree.ElementTree as ET 

html = '''<html> 
    <div>Some reasonably well-formed HTML content.</div> 
    <form action="login"> 
    <input name="foo" value="bar"/> 
    <input name="username"/><input name="password"/> 

    <div>It is not unusual to see &nbsp; in an HTML page.</div> 

    </form></html>''' 

magic = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [ 
      <!ENTITY nbsp ' '> 
      ]>''' # You can define more entities here, if needed 

et = ET.fromstring(magic + html) 
Các vấn đề liên quan