2013-06-25 87 views
0

我需要接受一些命令行參數,像這樣:使用Argparse轉換XML爲csv在python

argparse.py hi.xml --> to produce hi.csv or 
argparse.py hi.xml -o hello.csv --> to produce hello.csv 

這裏是我的代碼:

import os 
import sys 
import argparse 
import csv 
import indent 
from xml.etree.ElementTree import ElementTree, Element, SubElement, Comment, tostring 
import xml.etree.ElementTree as etree 

def get_args(args): 
    parser = argparse.ArgumentParser(description = "Converts CSV to XML") 
    parser.add_argument('-v','--verbose',action='store_true',dest='verbose',help='Increases messages being printed to stdout') 
    parser.add_argument("inputfile", help="Please input the name of the CSV file") 
    parser.add_argument('-o','--outputfile',help='(optional) Output file name',nargs='?') 
    args = parser.parse_args() 
    ext = os.path.splitext(args.inputfile)[1].lower() 
    if args.outputfile is None: 
     if ext == ".csv": 
      args.outputfile = os.path.splitext(args.inputfile)[0] + '.xml' 

     elif ext == ".xml": 
      args.outputfile = os.path.splitext(args.inputfile)[0] + '.csv' 

    elif args.outputfile: 
     if ext == ".csv": 
      outputfile = open(args.outputfile, 'w') 
     elif ext == ".xml": 
      outputfile = open(args.outputfile,'w') 
    else: 
     sys.stderr.write('ERROR: Invalid extension %s\n' % ext) 
     sys.exit(1) 
    return args 

def main(argv): 
    args = get_args(argv[0:]) 
    if args is None: 
     return 1 
    ext = os.path.splitext(args.inputfile)[1].lower() 
    if ext == ".csv": 
     reader = read_csv(open(args.inputfile)) 
     generate_xml(reader, args.outputfile) 

    if ext == ".xml": 
     root = etree.parse(open(args.inputfile)).getroot() 
     generate_csv(root, args.outputfile) 


    if args.verbose: 
     print ('Verbose Selected') 
    if args.verbose: 
     print ('Convert to XML with set name') 

    return 0 

def read_csv(inputfile): 
    return list(csv.reader(inputfile)) 

def generate_xml(reader,outfile): 
    root = Element('Solution') 
    root.set('version','1.0') 
    tree = ElementTree(root)   
    head = SubElement(root, 'DrillHoles') 
    description = SubElement(head,'description') 
    current_group = None 
    i = 0 
    for row in reader: 
     if i > 0: 
      x1,y1,z1,x2,y2,z2,cost = row 
      if current_group is None or i != current_group.text: 
       current_group = SubElement(description, 'hole',{'hole_id':"%s"%i}) 

       collar = SubElement (current_group, 'collar',{'':', '.join((x1,y1,z1))}), 
       toe = SubElement (current_group, 'toe',{'':', '.join((x2,y2,z2))}) 
       cost = SubElement(current_group, 'cost',{'':cost}) 
     i+=1 
    head.set('total_holes', '%s'%i) 
    indent.indent(root) 
    tree.write(outfile) 

def generate_csv(root, outfile): 

    with open(outfile, 'w') as file_: 

     writer = csv.writer(file_, delimiter="\t") 

    for a in zip(root.findall("drillholes/hole/collar"), 
       root.findall("drillholes/hole/toe"), 
       root.findall("drillholes/hole/cost")): 
     writer.writerow([x.text for x in a]) 

if (__name__ == "__main__"): 
    sys.exit(main(sys.argv)) 

我只是需要與generate_csv部分幫助。從函數get_args(args)中可以看到,我獲得了參數,這也是我使用ext = ....更改文件擴展名的地方,然後使用返回參數返回它。主函數調用該函數並獲取參數,然後再次檢查擴展,然後根據擴展導致下一個函數。在主函數中,我已經解析了xml文件,所以我只是將「root」和「args.outputfile」傳遞給generate_csv方法。然而,這是錯誤發生的地方:xml.etree.ElementTree.parserError:沒有找到第1行第0列的元素。但是,我相信這可能不是唯一的錯誤,也許我在某處丟失了參數改性。請幫忙

+0

您不需要將'args'傳遞給'get_args'函數。 ArgumentParser類知道從命令行查找參數。你實際上不需要將'sys.argv'傳遞給main。 –

回答

0

這不完全是一個簡單的例子,所以很難確切地確定你的問題是什麼以及具體問題是什麼。

錯誤提示解析器沒有輸入。這表明文件實際上是空的,或者文件指針已經被提前到文件的末尾。如果您不小心將其打開寫入並將其截斷爲零,該文件可能爲空。如果您意外地打開文件讀取文件,則可能會將文件指針提前到文件的末尾,從中讀取所有文件並忽略倒回文件指針。

因此,您可以看到發生了什麼,爲什麼不嘗試使用嬰兒步驟並在兩者之間打印的診斷?也就是說,不是etree.parse(open(args.inputfile)),你可以試試:

print(args.inputfile) 
f = open(args.inputfile) 
print(f.tell()) 
print(f.read()) 
f.seek(0) 
xml = etree.parse(f) 
print(xml) 
root = xml.getroot() 
print(root) 

這樣的話,你可以看到發生了什麼事情。

+0

對不起,xml文件本身有問題,但現在我修好了。無論如何,我在writer.writerow([x.text for x in a])行中得到另一個錯誤:關閉的文件上的I/O操作 – Andy

+0

這是因爲'writerow'不在'with open(outfile,') w')作爲file_:'construct - 注意'for'的縮進等級終止'with'並關閉相關文件。 – Emmet