2011-08-30 12 views
17

मेरे पास पार्स करने के लिए सुपर सरल एक्सएमएल फाइलों का एक सेट है ... लेकिन ... वे कस्टम परिभाषित इकाइयों का उपयोग करते हैं। मुझे इन्हें वर्णों में मैप करने की आवश्यकता नहीं है, लेकिन मैं प्रत्येक पर पार्स करना और कार्य करना चाहता हूं। उदाहरण के लिए:पायथन एलिमेंट ट्री समर्थन?

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

वहाँ http://effbot.org/elementtree/elementtree-xmlparser.htm पर एक tantalizing संकेत है कि XMLParser इकाई समर्थन सीमित है, लेकिन मैं तरीकों का उल्लेख नहीं मिल रहा है, सब कुछ त्रुटियों देता है:

#!/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 

कौन सा है आप कैसे पर निर्भर करता है टिप्पणियों को समायोजित करने देता है:

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

या

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

या

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

उत्सुक उन एक्सएमएल OpenStreetMap के mapnik परियोजना से है।

+0

संभवतः संबंधित सवाल: http://stackoverflow.com/questions/2524299/entity-references-and-lxml – unutbu

+0

, संबंधित इसलिए नहीं कि उस मामले में इकाई वास्तव में परिभाषित किया गया है। इकाई परिभाषा को हटाएं और आप मेरे प्रश्न पर वापस आ गए हैं। – Bryce

+0

fyi - कोई/usr/bin/python/usr/bin/env python को ठीक करना चाहता है क्योंकि शेबैंग लाइन अधिकांश सिस्टम के लिए गलत है। –

उत्तर

11

मुझे यकीन नहीं है कि यह ElementTree में क्या है या क्या है, लेकिन आपको अतीत में किए गए तरीके से व्यवहार करने के लिए एक्सपैट पार्सर पर UseForeignDTD (True) को कॉल करने की आवश्यकता है।

यह एक सा hacky है, लेकिन आप ElementTree.Parser का अपना स्वयं का उदाहरण बनाकर, विधि बुला यह xml.parsers.expat का उदाहरण है पर, और फिर इसे 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 

यह आउटपुट "MOOOOO"

या एक मानचित्रण इंटरफ़ेस का उपयोग:

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 

यह आउटपुट "moo_1"

ElementTree.XMLParser को उप-वर्गीकृत करने और इसे ठीक करने के लिए एक और जटिल फ़िक्स होगा।

+0

जैसा कि आप कहते हैं, थोड़ा सा icky, लेकिन धन्यवाद। संस्थाओं को पूर्वनिर्धारित करने से बचने का कोई तरीका है (उदा। और moo_2)। – Bryce

+0

@ ब्रिस: पूर्वनिर्धारित होना संस्थाओं का बिंदु है, नहीं? फिर भी: आप अपने स्वयं के शब्दकोश-जैसी वस्तु में 'parser.entity' सेट कर सकते हैं। एक साधारण उदाहरण के रूप में, आप 'parser.entity = संग्रह कर सकते हैं।डिफ़ॉल्ट डिस्प्ले (str) 'सभी अपरिभाषित इकाइयों को एक खाली स्ट्रिंग द्वारा प्रतिस्थापित करने के लिए। – Steven

+0

@ स्टीवन की टिप्पणी का पालन करने के लिए, आप मैपिंग इंटरफ़ेस को भी कार्यान्वित कर सकते हैं और जो भी आप चाबियों के साथ करना चाहते हैं। मैंने इसका जवाब एक साधारण उदाहरण दिखाने के लिए संपादित किया। – cnelson

3

के रूप में पहले से ही @cnelson एक टिप्पणी में कहा, चुने हुए समाधान यहाँ काम नहीं करेगा पायथन 3.

में मैं अंत में यह काम कर रहा मिला है। इस Q&A से उद्धृत।

this post से प्रेरित, हम आने वाली कच्ची HTML सामग्री में कुछ एक्सएमएल परिभाषा तैयार कर सकते हैं, और फिर एलिमेंटट्री बॉक्स से बाहर काम करेगा।

यह पायथन 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) 
संबंधित मुद्दे