2008-11-27 18 views
45

मैं वर्तमान में अजगर कुकबुक के अध्याय 12.5 के आधार पर निम्न कोड हूँ:पायथन में बड़े एक्सएमएल दस्तावेज़ों का विश्लेषण करने का सबसे तेज़ तरीका क्या है?

from xml.parsers import expat 

class Element(object): 
    def __init__(self, name, attributes): 
     self.name = name 
     self.attributes = attributes 
     self.cdata = '' 
     self.children = [] 
    def addChild(self, element): 
     self.children.append(element) 
    def getAttribute(self,key): 
     return self.attributes.get(key) 
    def getData(self): 
     return self.cdata 
    def getElements(self, name=''): 
     if name: 
      return [c for c in self.children if c.name == name] 
     else: 
      return list(self.children) 

class Xml2Obj(object): 
    def __init__(self): 
     self.root = None 
     self.nodeStack = [] 
    def StartElement(self, name, attributes): 
     element = Element(name.encode(), attributes) 
     if self.nodeStack: 
      parent = self.nodeStack[-1] 
      parent.addChild(element) 
     else: 
      self.root = element 
     self.nodeStack.append(element) 
    def EndElement(self, name): 
     self.nodeStack.pop() 
    def CharacterData(self,data): 
     if data.strip(): 
      data = data.encode() 
      element = self.nodeStack[-1] 
      element.cdata += data 
    def Parse(self, filename): 
     Parser = expat.ParserCreate() 
     Parser.StartElementHandler = self.StartElement 
     Parser.EndElementHandler = self.EndElement 
     Parser.CharacterDataHandler = self.CharacterData 
     ParserStatus = Parser.Parse(open(filename).read(),1) 
     return self.root 

मैं आकार में 1 जीबी के बारे में एक्सएमएल डॉक्स के साथ काम कर रहा हूँ। क्या किसी को इन्हें पार्स करने का एक तेज़ तरीका पता है?

+2

आपका प्रश्न बहुत किसी भी उपयोगी जवाब बटोरने के लिए अस्पष्ट है। इन सवालों के जवाब देने पर विचार करें: - आप इस 1 जीबी एक्सएमएल दस्तावेज़ के साथ क्या करने की कोशिश कर रहे हैं? - आपको इस पार्सर को कितनी तेजी से आवश्यकता है? - क्या आप आसानी से दस्तावेज के माध्यम से स्मृति में सबकुछ लोड करने की बजाय स्मृति को फिर से भर सकते हैं? – Matt

+2

मुझे इसे सब मेमोरी में लोड करने, डेटा को इंडेक्स करने और फिर 'ब्राउज' करने और इसे संसाधित करने की आवश्यकता है। –

उत्तर

52

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

नोट तथापि, cElementTree iterparse function के प्रयोग पर Fredriks सलाह:

बड़ी फ़ाइलों, आप तत्वों के रूप में जल्द ही छुटकारा पा सकते हैं पार्स करने के लिए आप उन्हें संसाधित होते:

for event, elem in iterparse(source): 
    if elem.tag == "record": 
     ... process record elements ... 
     elem.clear() 

उपर्युक्त पैटर्न में एक कमी है; यह रूट तत्व को साफ़ नहीं करता है, इसलिए आप एक ही तत्व के साथ समाप्त हो जाएंगे जिसमें बहुत से खाली बच्चे तत्व होंगे। यदि आपकी फाइलें बड़ी हैं, बल्कि बड़ी हैं, तो यह एक समस्या हो सकती है। इसके आसपास काम करने के लिए, आपको रूट तत्व पर अपने हाथों की आवश्यकता है।

# get an iterable 
context = iterparse(source, events=("start", "end")) 

# turn it into an iterator 
context = iter(context) 

# get the root element 
event, root = context.next() 

for event, elem in context: 
    if event == "end" and elem.tag == "record": 
     ... process record elements ... 
     root.clear() 

lxml.iterparse() इस अनुमति नहीं देता: यह करने के लिए सबसे आसान तरीका शुरू घटनाओं सक्षम करने के लिए, और एक चर में पहला तत्व के लिए एक संदर्भ बचाने के लिए है।

4

कॉलबैक पंजीकृत करना काफी हद तक पार्सिंग धीमा कर देता है। [संपादित करें] ऐसा इसलिए है क्योंकि (तेज़) सी कोड को पायथन दुभाषिया का आह्वान करना पड़ता है जो सी के रूप में तेज़ नहीं है। मूल रूप से, आप फ़ाइल को पढ़ने के लिए सी कोड का उपयोग कर रहे हैं (तेज़) और फिर पाइथन में डोम बनाएं (धीमी)। [/ EDIT]

xml.etree.ElementTree का उपयोग करने का प्रयास करें जो सी में 100% लागू किया गया है और जो बिना किसी कॉलबैक के पाइथन कोड के एक्सएमएल को पार्स कर सकता है।

दस्तावेज़ को पार्स करने के बाद, आप इसे प्राप्त करने के लिए फ़िल्टर कर सकते हैं।

यदि यह अभी भी बहुत धीमा है और आपको डीओएम की आवश्यकता नहीं है तो दूसरा विकल्प एक स्ट्रिंग में फ़ाइल को पढ़ने और इसे संसाधित करने के लिए सरल स्ट्रिंग ऑपरेशंस का उपयोग करना है।

+0

यह बहुत भ्रामक सलाह है। कॉलबैक-आधारित XML पार्सर के बारे में कुछ भी नहीं है जो आंतरिक रूप से धीमा है। इसके अलावा, ओपी पहले से ही पाइथन की एक्सपैट बाइंडिंग का उपयोग कर रहा है, जो देशी सी – Matt

+0

भी है पाइथन दुभाषिया हमेशा मूल रूप से संकलित सी कोड से धीमा है। और जैसा कि आप प्रश्न में कोड में स्पष्ट रूप से देख सकते हैं, यह पाइथन कोड को प्रत्येक तत्व के लिए बुलाया जा रहा है! और यह कोड भी बहुत काम करता है! –

+0

इसे ऊपर उठाया जाना चाहिए, पाइथन में कॉलबैक वास्तव में धीमी हैं, आप इससे बचना चाहते हैं और सी भूमि में जितना संभव हो उतना करना चाहते हैं। –

8

मैं आपको lxml का उपयोग करने की सलाह देता हूं, यह libxml2 लाइब्रेरी के लिए एक पायथन बाध्यकारी है जो वास्तव में तेज़ है।

मेरे अनुभव में, libxml2 और expat के समान प्रदर्शन है। लेकिन मैं libxml2 (और पायथन के लिए lxml) पसंद करते हैं क्योंकि ऐसा लगता है कि यह अधिक सक्रिय रूप से विकसित और परीक्षण किया जाता है। Libxml2 में और भी विशेषताएं हैं।

एलएक्सएमएल ज्यादातर xml.etree.ElementTree के साथ एपीआई संगत है। और इसकी वेबसाइट में अच्छा प्रलेखन है।

+2

एलएक्सएमएल नियम है! :) – ddaa

15

क्या आपने CElementTree मॉड्यूल की कोशिश की है?

cElementTree को Python 2.5 और बाद में, xml.etree.cElementTree के साथ शामिल किया गया है। benchmarks देखें।

हटाया मृत ImageShack लिंक

+0

छवि प्रदर्शित नहीं हो रही है: ( – fedorqui

4

यदि आपका आवेदन प्रदर्शन के प्रति संवेदनशील और बड़ी फ़ाइलों के सामने आ सकते हैं (जैसे आप ने कहा,> 1GB) तो मैं दृढ़ता से सलाह कोड आप कर रहे हैं का उपयोग कर के खिलाफ चाहते सरल कारण के लिए आपके प्रश्न में दिखा रहा है कि यह पूरे दस्तावेज़ को RAM में लोड करता है। मैं आपको एक बार में रैम में पूरे दस्तावेज़ पेड़ को पकड़ने से बचने के लिए अपने डिज़ाइन पर पुनर्विचार (यदि संभव हो) पर पुनर्विचार करने के लिए प्रोत्साहित करता हूं। यह नहीं जानना कि आपके आवेदन की क्या ज़रूरत है, मैं "घटना-आधारित" डिज़ाइन का उपयोग करने के लिए सलाह के सामान्य भाग के अलावा किसी भी विशिष्ट दृष्टिकोण का सही ढंग से सुझाव नहीं दे सकता।

0

स्पष्ट रूप से PyRXP वास्तव में तेज़ है।

वे दावा करते हैं कि यह सबसे तेज़ पार्सर है - लेकिन CElementTree उनकी आंकड़ों की सूची में नहीं है।

1

expat ParseFile अच्छी तरह से काम करता है अगर आप स्मृति में पूरे पेड़ स्टोर करने के लिए की जरूरत नहीं है, जो अभी या बाद में बड़ी फ़ाइलों के लिए अपने राम उड़ा देगा:

import xml.parsers.expat 
parser = xml.parsers.expat.ParserCreate() 
parser.ParseFile(open('path.xml', 'r')) 

यह टुकड़ों में फ़ाइलों को पढ़ता है, और राम को विस्फोट किए बिना उन्हें पार्सर में खिलाता है।

डॉक्टर: https://docs.python.org/2/library/pyexpat.html#xml.parsers.expat.xmlparser.ParseFile

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

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