首页 > 深入Python > XML处理 > 提取输入源 | << >> | ||||
diveintopython.org Python for experienced programmers |
Python的最强大力量之一是它的动态绑定(binding),并且动态绑定最强大的用法之一是类文件(file-like)对象。
许多需要输入源的函数可以简单地接收一个文件名,以读方式打开文件,读出它,处理完后关毕它。但这些函数不是这样的。相反,它们接收一个类文件对象。
在最简单的例子中,类文件对象是任意一个带有 read 方法的对象。这个方法带一个可选的 size 参数,并返回一个字符串。当不用 size 参数调用时,它从输入源中读出所有东西,并将所有数据作为单个字符串返回。当使用 size 参数调用时,它从输入源中读出 size 大小的数据,并返回那些数据;当再次调用时,它从余下的地方开始并返回下一块数据。
上面就是从真正文件中读取是如何工作的;区别就在于我们没有把自已局限于真正的文件。输入源可以是任何东西:磁盘上的文件,网页,甚至可以是一个硬编码的字符串。只要我们将一个类文件对象传给函数,只需要调用对象的 read 方法,就可以处理任何类型的输入源,而不需要处理每种类型的特别代码。
一旦你想知道这与XML处理有什么关系,minidom.parse 就是这样一个可以接收类文件对象的函数。
>>> from xml.dom import minidom >>> fsock = open('binary.xml') >>> xmldoc = minidom.parse(fsock) >>> fsock.close() >>> print xmldoc <?xml version="1.0" ?> <grammar> <ref id="bit"> <p>0</p> <p>1</p> </ref> <ref id="byte"> <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\ <xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p> </ref> </grammar>
首先,我们打开磁盘上的文件。这会提供给我们一个文件对象。 | |
我们将文件对象传给 minidom.parse,它调用 fsock 的 read 方法,并从磁盘上的文件中读出XML文档。 | |
要确保在我们处理完文件对象之后调用 close 方法。minidom.parse 不会替你做这件事。 |
哦,所有这些看上去象是在浪费大量的时间。毕竟我们已经看到过 minidom.parse 可以只接收文件名,并自动执行所有打开和关闭不再用的文件。不错,如果你知道正要分析一个本地文件,你是可以传递文件名,且 minidom.parse 可以足够灵活地“做正确的事”。但请注意,使用类文件对象直接从Internet来分析XML文档是多么相似和容易呀。
>>> import urllib >>> usock = urllib.urlopen('http://slashdot.org/slashdot.rdf') >>> xmldoc = minidom.parse(usock) >>> usock.close() >>> print xmldoc.toxml() <?xml version="1.0" ?> <rdf:RDF xmlns="http://my.netscape.com/rdf/simple/0.9/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <channel> <title>Slashdot</title> <link>http://slashdot.org/</link> <description>News for nerds, stuff that matters</description> </channel> <image> <title>Slashdot</title> <url>http://images.slashdot.org/topics/topicslashdot.gif</url> <link>http://slashdot.org/</link> </image> <item> <title>To HDTV or Not to HDTV?</title> <link>http://slashdot.org/article.pl?sid=01/12/28/0421241</link> </item> [...略...]
正如我们在前一章所看到的,urlopen 接收一个web页面的URL并返回一个类文件对象。最重要的是,这个对象有一个 read 方法,它可以返回web页面的HTML源代码。 | |
现在我们将类文件对象传给 minidom.parse,它顺从地调用对象的 read 方法并对 read 方法所返回的XML数据进行分析。这与XML数据现在是直接从一个web页面来的事实毫不相干。minidom.parse 不了解web页面,同时也不关心;它只知道类文件对象。 | |
一理你处理完毕,确保将 urlopen 提供给你的类文件对象关闭了。 | |
随便说一句,这个URL是真实的,它真是一个XML。它是位于Slashdot站点上的当前标题的XML表示,一条技术新闻和站点一瞥。 |
>>> contents = "<grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar>" >>> xmldoc = minidom.parseString(contents) >>> print xmldoc.toxml() <?xml version="1.0" ?> <grammar><ref id="bit"><p>0</p><p>1</p></ref></grammar>
如果有一个方法可以把字符串转换成类文件对象,那么我们可以只把这个对象传递给 minidom.parse 就可以了。事实上,有一个专门设计好的用来做这种事的模块: StringIO。
>>> contents = "<grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar>" >>> import StringIO >>> ssock = StringIO.StringIO(contents) >>> ssock.read() "<grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar>" >>> ssock.read() '' >>> ssock.seek(0) >>> ssock.read(15) '<grammar><ref i' >>> ssock.read(15) "d='bit'><p>0</p" >>> ssock.read() '><p>1</p></ref></grammar>' >>> ssock.close()
>>> contents = "<grammar><ref id='bit'><p>0</p><p>1</p></ref></grammar>" >>> ssock = StringIO.StringIO(contents) >>> xmldoc = minidom.parse(ssock) >>> print xmldoc.toxml() <?xml version="1.0" ?> <grammar><ref id="bit"><p>0</p><p>1</p></ref></grammar>
那么现在我们知道了如何使用单个函数,minidom.parse,来分析存放在web页面中,本地文件中,或硬编码字符串中的XML文档。对于web页面,我们使用 urlopen 得到类文件对象;对于本地文件,我们使用 open;对于字符串,我们使用 StringIO。现在让我们更深一步同时也把这些不同之处归纳一下。
def openAnything(source): # try to open with urllib (if source is http, ftp, or file URL) import urllib try: return urllib.urlopen(source) except (IOError, OSError): pass # try to open with native open function (if source is pathname) try: return open(source) except (IOError, OSError): pass # assume source is string import StringIO return StringIO.StringIO(source)
现在我们可以使用这个 openAnything 函数同 minidom.parse 联系起来生成一个函数,它接收一个一个不知从哪来的XML文档,source (或者为一个URL,或一个本地文件,或在一个字符串中的硬编码XML文档)并分析它。
访问元素属性 |
1 2 3 4 5 6 7 8 9 | 标准输入,输出和错误 |