2013-12-18 154 views
4

有一個簡單的XMLPython的使用LXML用的FileInput

<?xml version="1.0" encoding="UTF-8" ?> 
<root> 
    <child>abc</child> 
</root> 

我想從文件中解析它,並且這工作得很好:

with open('tst.xml') as test_xml: 
    for _, element in lxml.etree.iterparse(test_xml, tag='child'): 
     print element.text # prints abc as expected 

不過,我試圖修改腳本,然後允許它解析XML無論是從文件或stdin並沒有成功:

fi = fileinput.input('tst.xml') 
for _, element in lxml.etree.iterparse(fi, tag='child'): 
    print element.text 

# File "iterparse.pxi", line 371, in lxml.etree.iterparse.__init__ (src/lxml/lxml.etree.c:97283) 
# File "apihelpers.pxi", line 1411, in lxml.etree._encodeFilename (src/lxml/lxml.etree.c:22515) 
# TypeError: Argument must be string or unicode. 

我不知道在什麼我做錯了。在Python中,FileInput對象不是文件類對象嗎?

+0

也許'lxml.etree.iterparse()'僅處理一個真正的文件,並沒有任何類似文件的對象。 –

+0

這可能不是真的,因爲'sys.stdin'被認爲是一個類似文件的對象,並且被'iterparse()'解析沒有任何問題。 – Ixanezis

+0

在Python 2.x中,'sys.stdin'默認是一個真實的文件對象 - 我的意思是它的'type()'是'file'。 'fileinput.input()'不是這種情況。請注意後者有一個'fileno()'方法,但它返回-1。我不確定讓一個返回-1的方法'fileno()'有什麼意義,因爲任何試圖通過查詢文件描述符來嘗試使用文件類對象的C代碼都會嘗試使用-1 .. 。 –

回答

0

你不應該嘗試使用fileinput模塊,而是直接做這樣的:

if filename == '-': # or, if we don't have a filename argument 
    f = sys.stdin 
else: 
    f = open(filename, 'r') 
+0

但是..爲什麼?您的方法不能提供正確的結賬處理。如果f不是sys.stdin:f.close()',那麼我將不得不編寫樣板文件,並且它不是異常安全的。 – Ixanezis

+0

您使用fileinput'的'不提供正確處理收盤要麼...其實'fileinput'是一個很老的Python模塊,所以不能用'with'聲明相結合。如何使用'try:finally:'?我同意這是幾行樣板,但我不知道任何更緊湊的解決方案,對不起。 –

+0

我簡化我的例子儘可能的,它看起來像'與contextlib.closing(fileinput.input(args.input))作爲輸入:'在現實世界中,它提供了必要的異常安全,並努力正確的,因爲'的FileInput ''close()'方法檢查'sys.stdin'並且不關閉它。無論如何,感謝您的幫助。 – Ixanezis

1

沒有深入的調查,似乎是一個例外的原因是FileInput類不提供read方法。 爲了實現我的目標,我結束了寫我自己的包裝,現在:

class FileInput(object): 
    def __init__(self, filename=None, *args, **kwargs): 
     self.file = open(filename, *args, **kwargs) if filename and filename != "-" else sys.stdin 

    def __enter__(self): 
     return self.file 

    def __exit__(self, type, value, traceback): 
     if self.file is not sys.stdin: 
      self.file.close() 

    def __getattr__(self, name): 
     return getattr(self.file, name) 

我會雖然等待一個更好的答案。