|
5 | 5 | ---------- |
6 | 6 | 问题 |
7 | 7 | ---------- |
8 | | -todo... |
| 8 | +你想从一个简单的XML文档中提取数据。 |
| 9 | + |
| 10 | +| |
9 | 11 |
|
10 | 12 | ---------- |
11 | 13 | 解决方案 |
12 | 14 | ---------- |
13 | | -todo... |
| 15 | +可以使用 ``xml.etree.ElementTree`` 模块从简单的XML文档中提取数据。 |
| 16 | +为了演示,假设你想解析Planet Python上的RSS源。下面是相应的代码: |
| 17 | + |
| 18 | +.. code-block:: python |
| 19 | +
|
| 20 | + from urllib.request import urlopen |
| 21 | + from xml.etree.ElementTree import parse |
| 22 | +
|
| 23 | + # Download the RSS feed and parse it |
| 24 | + u = urlopen('http://planet.python.org/rss20.xml') |
| 25 | + doc = parse(u) |
| 26 | +
|
| 27 | + # Extract and output tags of interest |
| 28 | + for item in doc.iterfind('channel/item'): |
| 29 | + title = item.findtext('title') |
| 30 | + date = item.findtext('pubDate') |
| 31 | + link = item.findtext('link') |
| 32 | +
|
| 33 | + print(title) |
| 34 | + print(date) |
| 35 | + print(link) |
| 36 | + print() |
| 37 | +
|
| 38 | +运行上面的代码,输出结果类似这样: |
| 39 | + |
| 40 | +.. code-block:: python |
| 41 | +
|
| 42 | + Steve Holden: Python for Data Analysis |
| 43 | + Mon, 19 Nov 2012 02:13:51 +0000 |
| 44 | + http://holdenweb.blogspot.com/2012/11/python-for-data-analysis.html |
| 45 | +
|
| 46 | + Vasudev Ram: The Python Data model (for v2 and v3) |
| 47 | + Sun, 18 Nov 2012 22:06:47 +0000 |
| 48 | + http://jugad2.blogspot.com/2012/11/the-python-data-model.html |
| 49 | +
|
| 50 | + Python Diary: Been playing around with Object Databases |
| 51 | + Sun, 18 Nov 2012 20:40:29 +0000 |
| 52 | + http://www.pythondiary.com/blog/Nov.18,2012/been-...-object-databases.html |
| 53 | +
|
| 54 | + Vasudev Ram: Wakari, Scientific Python in the cloud |
| 55 | + Sun, 18 Nov 2012 20:19:41 +0000 |
| 56 | + http://jugad2.blogspot.com/2012/11/wakari-scientific-python-in-cloud.html |
| 57 | +
|
| 58 | + Jesse Jiryu Davis: Toro: synchronization primitives for Tornado coroutines |
| 59 | + Sun, 18 Nov 2012 20:17:49 +0000 |
| 60 | + http://feedproxy.google.com/~r/EmptysquarePython/~3/_DOZT2Kd0hQ/ |
| 61 | +
|
| 62 | +很显然,如果你想做进一步的处理,你需要替换 ``print()`` 语句来完成其他有趣的事。 |
| 63 | +
|
| 64 | +| |
14 | 65 |
|
15 | 66 | ---------- |
16 | 67 | 讨论 |
17 | 68 | ---------- |
18 | | -todo... |
| 69 | +在很多应用程序中处理XML编码格式的数据是很常见的。 |
| 70 | +不仅是因为XML在Internet上面已经被广泛应用于数据交换, |
| 71 | +同时它也是一种存储应用程序数据的常用格式(比如字处理,音乐库等)。 |
| 72 | +接下来的讨论会先假定读者已经对XML基础比较熟悉了。 |
| 73 | +
|
| 74 | +在很多情况下,当使用XML来仅仅存储数据的时候,对应的文档结构非常紧凑并且直观。 |
| 75 | +例如,上面例子中的RSS订阅源类似于下面的格式: |
| 76 | +
|
| 77 | +.. code-block:: python |
| 78 | +
|
| 79 | + <?xml version="1.0"?> |
| 80 | + <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> |
| 81 | + <channel> |
| 82 | + <title>Planet Python</title> |
| 83 | + <link>http://planet.python.org/</link> |
| 84 | + <language>en</language> |
| 85 | + <description>Planet Python - http://planet.python.org/</description> |
| 86 | + <item> |
| 87 | + <title>Steve Holden: Python for Data Analysis</title> |
| 88 | + <guid>http://holdenweb.blogspot.com/...-data-analysis.html</guid> |
| 89 | + <link>http://holdenweb.blogspot.com/...-data-analysis.html</link> |
| 90 | + <description>...</description> |
| 91 | + <pubDate>Mon, 19 Nov 2012 02:13:51 +0000</pubDate> |
| 92 | + </item> |
| 93 | + <item> |
| 94 | + <title>Vasudev Ram: The Python Data model (for v2 and v3)</title> |
| 95 | + <guid>http://jugad2.blogspot.com/...-data-model.html</guid> |
| 96 | + <link>http://jugad2.blogspot.com/...-data-model.html</link> |
| 97 | + <description>...</description> |
| 98 | + <pubDate>Sun, 18 Nov 2012 22:06:47 +0000</pubDate> |
| 99 | + </item> |
| 100 | + <item> |
| 101 | + <title>Python Diary: Been playing around with Object Databases</title> |
| 102 | + <guid>http://www.pythondiary.com/...-object-databases.html</guid> |
| 103 | + <link>http://www.pythondiary.com/...-object-databases.html</link> |
| 104 | + <description>...</description> |
| 105 | + <pubDate>Sun, 18 Nov 2012 20:40:29 +0000</pubDate> |
| 106 | + </item> |
| 107 | + ... |
| 108 | + </channel> |
| 109 | + </rss> |
| 110 | +
|
| 111 | +``xml.etree.ElementTree.parse()`` 函数解析整个XML文档并将其转换成一个文档对象。 |
| 112 | +然后,你就能使用 ``find()`` 、``iterfind()`` 和 ``findtext()`` 等方法来搜索特定的XML元素了。 |
| 113 | +这些函数的参数就是某个指定的标签名,例如 ``channel/item`` 或 ``title`` 。 |
| 114 | +
|
| 115 | +每次指定某个标签时,你需要遍历整个文档结构。每次搜索操作会从一个起始元素开始进行。 |
| 116 | +同样,每次操作所指定的标签名也是起始元素的相对路径。 |
| 117 | +例如,执行 ``doc.iterfind('channel/item')`` 来搜索所有在 ``channel`` 元素下面的 ``item`` 元素。 |
| 118 | +``doc`` 代表文档的最顶层(也就是第一级的 ``rss`` 元素)。 |
| 119 | +然后接下来的调用 ``item.findtext()`` 会从已找到的 ``item`` 元素位置开始搜索。 |
| 120 | +
|
| 121 | +``ElementTree`` 模块中的每个元素有一些重要的属性和方法,在解析的时候非常有用。 |
| 122 | +``tag`` 属性包含了标签的名字,``text`` 属性包含了内部的文本,而 ``get()`` 方法能获取属性值。例如: |
| 123 | +
|
| 124 | +.. code-block:: python |
| 125 | +
|
| 126 | + >>> doc |
| 127 | + <xml.etree.ElementTree.ElementTree object at 0x101339510> |
| 128 | + >>> e = doc.find('channel/title') |
| 129 | + >>> e |
| 130 | + <Element 'title' at 0x10135b310> |
| 131 | + >>> e.tag |
| 132 | + 'title' |
| 133 | + >>> e.text |
| 134 | + 'Planet Python' |
| 135 | + >>> e.get('some_attribute') |
| 136 | + >>> |
| 137 | +
|
| 138 | +有一点要强调的是 ``xml.etree.ElementTree`` 并不是XML解析的唯一方法。 |
| 139 | +对于更高级的应用程序,你需要考虑使用 ``lxml`` 。它使用了和ElementTree同样的编程接口, |
| 140 | +因此上面的例子同样也适用于lxml。你只需要将刚开始的import语句换成 ``lxml.etree import parse`` 就行了。 |
| 141 | +``lxml`` 完全遵循XML标准,并且速度也非常快,同时还支持验证,XSLT和XPath等特性。 |
0 commit comments