2009-10-03 12 views
8

मैं "फ्लाई पर" एक बड़ी एक्सएमएल फ़ाइल पार्स करना चाहता हूं। मैं इसे करने के लिए एक अजगर जनरेटर का उपयोग करना चाहता हूं। मैंने "xml.etree.cElementTree" (जो वास्तव में अच्छा है) "iterparse" की कोशिश की है लेकिन अभी भी जनरेटर नहीं है।पायथन: क्या एक एक्सएमएल पार्सर जेनरेटर के रूप में लागू किया गया है?

अन्य सुझाव?

उत्तर

6

"फ्लाई ऑन" पार्सिंग और दस्तावेज़ पेड़ वास्तव में संगत नहीं हैं। सैक्स-शैली पार्सर्स आमतौर पर इसके लिए उपयोग किए जाते हैं (उदाहरण के लिए, पायथन का मानक xml.sax)। आपको मूल रूप से स्टार्ट एलीमेंट, एंडलेमेंट इत्यादि जैसी विभिन्न घटनाओं के लिए हैंडलर के साथ एक कक्षा को परिभाषित करना होगा और पार्सर विधियों को कॉल करेगा क्योंकि यह XML फ़ाइल को पार करता है।

+1

यही वही है जो मुझे चाहिए ... मुझे "स्टार्ट टैग" जैसी घटनाओं पर "प्रतिक्रिया" करने की कोई बात नहीं है। – jldupont

+1

@ जीन-लो: अगर आपको पूरे पेड़ की आवश्यकता नहीं है, तो SAX है जाने के लिए रास्ता। यह सामग्री के पेड़ की बजाय घटनाओं की धारा के रूप में दस्तावेजों को संसाधित करने के लिए किया जाता है। –

4

PullDom जो आप चाहते हैं वह करता है। यह एसएक्स की तरह एक स्ट्रीम से एक्सएमएल पढ़ता है, लेकिन उसके बाद एक चयनित टुकड़े के लिए एक डोम बनाता है।

"पुलडॉम एक मोनोलिथिक पेड़ की बजाय स्ट्रीमिंग (कुशल!) तरीके से डीओएम ऑब्जेक्ट्स के साथ काम करने के लिए एक बहुत ही सरल एपीआई है।"

+0

इसलिए यदि मैं फॉर-लूप {उदा। घटनाओं में (घटना, नोड) के लिए: उपज (घटना, नोड)} अगली बार जब मैं फॉर-लूप में प्रवेश करता हूं तो पुलडॉम फिर से शुरू नहीं होगा? – jldupont

+0

... क्योंकि यह "iterparse" के साथ होता है ... – jldupont

+0

@ जीन-लो डुपॉन्ट: यदि आप इटेटरेटर व्यवहार चाहते हैं, तो शायद आपको ElementTree ऑब्जेक्ट पर 'iter (...)' को कॉल करना चाहिए? – u0b34a0f6ae

15

xml.etree.cElementTree सही उपयोग के साथ जनरेटर के करीब आता है; डिफ़ॉल्ट रूप से आप प्रत्येक 'तत्व' घटना के बाद प्रत्येक तत्व प्राप्त करते हैं, जिस बिंदु पर आप इसे संसाधित कर सकते हैं। यदि आपको प्रोसेसिंग के बाद इसकी आवश्यकता नहीं है तो आपको तत्व पर element.clear() का उपयोग करना चाहिए; इस प्रकार आप स्मृति को बचाते हैं।


यहां मेरा पूरा अर्थ है, जहां मैं रिदमम्क्स (संगीत प्लेयर) लाइब्रेरी का विश्लेषण करता हूं। मैं (सी) ElementTree के iterparse का उपयोग करता हूं और प्रत्येक संसाधित तत्व के लिए मैं element.clear() को कॉल करता हूं ताकि मैं काफी मेमोरी बचा सकूं। (बीटीडब्ल्यू, नीचे दिया गया कोड कुछ सैक्स कोड को एक ही काम करने के लिए उत्तराधिकारी है; सीमेंटमेंट ट्री समाधान 1 से एक राहत थी) कोड संक्षिप्त है और मुझे जो चाहिए वह व्यक्त करता है और कुछ भी नहीं 2) यह 3x तेज है, 3) यह कम स्मृति का उपयोग करता है।)

import os 
import xml.etree.cElementTree as ElementTree 
NEEDED_KEYS= set(("title", "artist", "album", "track-number", "location",)) 

def _lookup_string(string, strmap): 
    """Look up @string in the string map, 
    and return the copy in the map. 

    If not found, update the map with the string. 
    """ 
    string = string or "" 
    try: 
     return strmap[string] 
    except KeyError: 
     strmap[string] = string 
     return string 

def get_rhythmbox_songs(dbfile, typ="song", keys=NEEDED_KEYS): 
    """Return a list of info dictionaries for all songs 
    in a Rhythmbox library database file, with dictionary 
    keys as given in @keys. 
    """ 
    rhythmbox_dbfile = os.path.expanduser(dbfile) 

    lSongs = [] 
    strmap = {} 

    # Parse with iterparse; we get the elements when 
    # they are finished, and can remove them directly after use. 

    for event, entry in ElementTree.iterparse(rhythmbox_dbfile): 
     if not (entry.tag == ("entry") and entry.get("type") == typ): 
      continue 
     info = {} 
     for child in entry.getchildren(): 
      if child.tag in keys: 
       tag = _lookup_string(child.tag, strmap) 
       text = _lookup_string(child.text, strmap) 
       info[tag] = text 
     lSongs.append(info) 
     entry.clear() 
    return lSongs 

अब, मैं अपनी उम्मीदों समझ में नहीं आता, तो आपको निम्न उम्मीद है?

# take one 
for event, entry in ElementTree.iterparse(rhythmbox_dbfile): 
    # parse some entries, then exit loop 

# take two 
for event, entry in ElementTree.iterparse(rhythmbox_dbfile): 
    # parse the rest of entries 

हर बार जब आप iterparse फोन आप एक नया इटरेटर वस्तु मिलता है, नए सिरे से फ़ाइल को पढ़ने! आप इटरेटर अर्थ विज्ञान के साथ एक लगातार वस्तु चाहते हैं, आप दोनों छोरों में एक ही वस्तु (अपरीक्षित कोड) का उल्लेख करना होगा:

#setup 
parseiter = iter(ElementTree.iterparse(rhythmbox_dbfile)) 
# take one 
for event, entry in parseiter: 
    # parse some entries, then exit loop 

# take two 
for event, entry in parseiter: 
    # parse the rest of entries 

मुझे लगता है कि के बाद से विभिन्न वस्तुओं अलग अर्थ विज्ञान है यह भ्रामक हो सकते हैं। फ़ाइल ऑब्जेक्ट में हमेशा एक आंतरिक स्थिति होगी और फ़ाइल में अग्रिम होगा, हालांकि आप इसे फिर से चालू करेंगे। स्पष्ट रूप से एक ElementTree iterparse वस्तु नहीं है। क्रूक्स यह सोचने के लिए है कि जब आप लूप का उपयोग करते हैं, तो हमेशा उस चीज पर इसे हमेशा कॉलर() कहते हैं।

>>> import xml.etree.cElementTree as ElementTree 
>>> pth = "/home/ulrik/.local/share/rhythmbox/rhythmdb.xml" 
>>> iterparse = ElementTree.iterparse(pth) 
>>> iterparse 
<iterparse object at 0x483a0890> 
>>> iter(iterparse) 
<generator object at 0x483a2f08> 
>>> iter(iterparse) 
<generator object at 0x483a6468> 
>>> f = open(pth, "r") 
>>> f 
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98> 
>>> iter(f) 
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98> 
>>> iter(f) 
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98> 

क्या आप देखते हैं कि प्रत्येक कॉल() एक iterparse वस्तु पर आईटीईआर के लिए है एक नया जनरेटर रिटर्न: यहाँ एक प्रयोग एक फ़ाइल वस्तु के साथ ElementTree.iterparse की तुलना है। फ़ाइल ऑब्जेक्ट में, एक आंतरिक ऑपरेटिंग सिस्टम स्थिति है जिसे संरक्षित किया जाना चाहिए और यह स्वयं का इटरेटर है।

+0

@kaizer: तो असल में यह तत्व के बाद प्रत्येक बार फॉर-लूप दर्ज होने पर दस्तावेज़ के सबसेट के साथ काम करने जैसा है। – jldupont

+0

आपने परिभाषित नहीं किया है कि आप क्या करना चाहते हैं और आपकी अपेक्षाएं मुझे आश्चर्यचकित करती हैं; मैं पूरे दस्तावेज़ पर लूप के लिए एक में इसका उपयोग करूँगा। मैं एक उदाहरण बनाउंगा। – u0b34a0f6ae

+0

@kaizer: आपके सभी प्रयासों के लिए बहुत धन्यवाद। मैंने इस पोस्ट के लिए सैक्स पार्सर धन्यवाद की खोज की और ऐसा लगता है कि मैं इस दृष्टिकोण के साथ अपने राज्य-मशीन आधारित पार्सर को अच्छी तरह से प्रबंधित करने में सक्षम हूं। (क्या आप बता सकते हैं कि मैं एक एक्सएमएल-नौसिखिया हूं? ;-) – jldupont

0

यह ElementTree और वृद्धिशील पार्स के साथ संभव है: http://effbot.org/zone/element-iterparse.htm#incremental-parsing

import xml.etree.cElementTree as etree 
for event, elem in etree.iterparse(source): 
    ... 

आसान सैक्स से उपयोग करने के लिए।

+0

@jldupont: आपका प्रश्न कहता है कि आपने कोशिश की है (दो साल पहले): "" "मैंने कोशिश की है" xml.etree.cElementTree "(जो वास्तव में अच्छा है)" " –

+0

-1 बड़ी फ़ाइल का मतलब है cElementTree का उपयोग करें (जिसे ओपी राज्यों को पहले ही कोशिश की जा चुकी है!) ... क्या आपने @ kaiser.se द्वारा जवाब नहीं पढ़ा? –

संबंधित मुद्दे