2011-03-24 25 views
2

我需要定期從我們的管理軟件導出XML文件。用Python解析XML xml.sax:如何「跟蹤」樹中的哪個位置?

這是我第一次在Python中使用XML解析。與xml.sax的XML不是非常困難,但是「跟蹤」您在XML樹中的哪個位置的最佳方法是什麼?

例如,我有我們的客戶名單。我想提取的電話,但有多個地方出現:

eExact -> Accounts -> Account -> Contacts -> Contact -> Addresses -> Address -> Phone 
eExact -> Accounts -> Account -> Contacts -> Contact -> Phone 
eExact -> Accounts -> Account -> Phone 

所以我需要保持跟蹤我才能在XML樹到底在哪得到電話號碼

據我可以從Python網站上的xml.sax文檔中找到,沒有設置「easy」方法或變量。

所以,這就是我所做的:

import xml.sax 

class Exact(xml.sax.handler.ContentHandler): 
    def __init__(self): 
    self.curpath = [] 

    def startElement(self, name, attrs): 
    self.curpath.append(name) 

    if name == 'Phone': 
     print self.curpath, name 

    def endElement(self, name): 
    self.curpath.pop() 

if __name__ == '__main__': 
    parser = xml.sax.make_parser() 
    handler = Exact() 
    parser.setContentHandler(handler) 
    parser.parse(open('/home/cronuser/xml/mount/daily/debtors.xml')) 

這不是很困難的,但因爲我沒有很多與XML的經驗,我不知道這個「普遍接受」或「最好的可能「的方式?

謝謝:)

回答

2

感謝或所有評論。

我看着ElementTree的iterparse,但到那時我已經在xml.sax中做了相當多的代碼。由於iterparse的直接優勢是不存在的,所以我選擇只使用xml.sax。與目前的解決方案相比,這已經是一大優勢。

好的,所以這是我最後做的。

class Exact(xml.sax.handler.ContentHandler): 
    def __init__(self, stdpath): 
     self.stdpath = stdpath 

     self.thisrow = {} 
     self.curpath = [] 
     self.getvalue = None 

     self.conn = MySQLConnect() 
     self.table = None 
     self.numrows = 0 

    def __del__(self): 
     self.conn.close() 

     print '%s rows affected' % self.numrows 

    def startElement(self, name, att): 
     self.curpath.append(name) 

    def characters(self, data): 
     if self.getValue is not None: 
      self.thisrow[self.getValue.strip()] = data.strip() 
      self.getValue = None 

    def endElement(self, name): 
     self.curpath.pop() 

     if name == self.stdpath[len(self.stdpath) - 1]: 
      self.EndRow() 
      self.thisrow = { } 

    def EndRow(self): 
     self.numrows += MySQLInsert(self.conn, self.thisrow, True, self.table) 
     #for k, v in self.thisrow.iteritems(): 
     # print '%s: %s,' % (k, v), 
     #print '' 

    def curPath(self, full=False): 
     if full: 
      return ' > '.join(self.curpath) 
     else: 
      return ' > '.join(self.curpath).replace(' > '.join(self.stdpath) + ' > ', '') 

我那麼這個子類爲不同的XML文件的次數:

class Debtors(sqlimport.Exact): 
    def startDocument(self): 
     self.table = 'debiteuren' 
     self.address = None 

    def startElement(self, name, att): 
     sqlimport.Exact.startElement(self, name, att) 

     if self.curPath(True) == ' > '.join(self.stdpath): 
      self.thisrow = {} 
      self.thisrow['debiteur'] = att.get('code').strip() 
     elif self.curPath() == 'Name': 
      self.getValue = 'naam' 
     elif self.curPath() == 'Phone': 
      self.getValue = 'telefoon1' 
     elif self.curPath() == 'ExtPhone': 
      self.getValue = 'telefoon2' 
     elif self.curPath() == 'Contacts > Contact > Addresses > Address': 
      if att.get('type') == 'V': 
       self.address = 'Contacts > Contact > Addresses > Address ' 
     elif self.address is not None: 
      if self.curPath() == self.address + '> AddressLine1': 
       self.getValue = 'adres1' 
      elif self.curPath() == self.address + '> AddressLine2': 
       self.getValue = 'adres2' 
     else: 
      self.getValue = None 

if __name__ == '__main__': 
    handler = Debtors(['Debtors', 'Accounts', 'Account']) 
    parser = xml.sax.make_parser() 
    parser.setContentHandler(handler) 

    parser.parse(open('myfile.xml', 'rb')) 

...等等...

1

我認爲最簡單的辦法是你在做你的榜樣正是 - 保持節點的堆棧。

2

是否有一個特定的原因需要使用SAX?

因爲如果將整個XML文件加載到內存中的對象模型是可以接受的,那麼您可能會發現使用ElementTree DOM API會更容易。如果你不需要在給定孩子時檢索父節點的能力,那麼Python標準庫中的cElementTree應該很好地實現這個技巧,如果你這樣做,LXML庫提供了一個ElementTree實現,你的父母引用。兩個使用編譯的C模塊的速度。)

+0

XML文件超過100MB,每年增長約100MB,所以這不是一個選項。 – Carpetsmoker 2011-03-24 14:07:03

+0

在這種情況下,我的下一個建議將是ElementTree的iterparse,但dw0rm擊敗了我...雖然我可憐你必須做你正在做的事情。這聽起來像是一個應該使用XML以外的工作完成的工作。 (可能是一個數據庫) – ssokolow 2011-03-25 00:56:28

+0

是的,不要讓我開始* *這不幸的是......這是唯一可用的解決方案... – Carpetsmoker 2011-03-25 01:15:40

4

我也使用薩克斯,但後來我發現了一個更好的工具:iterparse from ElementTree

與sax類似,但您可以檢索包含內容的元素,以釋放內存,您只需清除元素即可。