使用 Python 和 pureXML 操作 CSV 数据

在 IBM DB2 Express-C 中使用 Python 导入美国人口普查数据并转换成 XML

IBM® DB2® pureXML® 允许您将 XML 数据原生地储存在关系数据库管理系统中,从而允许您灵活地创建数据报告,并且仍然能够利用 XML 的优势。在本教程中,您将学习如何使用 Python 编程语言连接到 DB2 数据库,然后导入来自美国人口普查局的人口数据。在将 XML 数据原生地插入到 DB2 之前,您将使用 Python 把 CSV 文件转换成 XML。最后,您将使用 Python 创建一个命令行应用程序,它将生成一些可以通过菜单系统访问的信息表。

Joe Lennon, 软件开发人员, Freelance

http://www.ibm.com/developerworks/i/p-jlennon.jpgJoe Lennon 是一位来自爱尔兰科克市的软件开发人员,他今年 23 岁。Joe 目前为 Core International 工作,是 Web 应用程序和 Oracle PL/SQL 开发人员。他 2007 年毕业于 University College Cork,并获得商业信息系统专业的学位。他现在和他的女朋友 Jill 生活在科克市。



2010 年 2 月 04 日

开始之前

本教程主要针对希望了解如何以 XML 格式将数据存储在数据库中、从 Python 应用程序连接到 DB2 以及将数据从 CSV 文件转换成 XML 文档的开发人员。学习本教程不要求具备 Python 的知识(您将在本教程中了解如何安装 Python),但具有相关知识会有所帮助。本教程假设您使用 Microsoft® Windows® 操作系统,但所用的代码应该可用于其他操作系统。在学习完本教程之后,您将能够创建强大的 Python 应用程序,它可以与 IBM DB2 数据库交互并利用 pureXML 提供的功能。

关于本教程

常用缩略词

  • API:应用编程接口
  • CSV:逗号分隔值
  • DBA:数据库管理员
  • SQL:结构化查询语言
  • UI:用户界面
  • URL:统一资源定位符
  • XML:可扩展标记语言

IBM DB2 数据库管理系统早就成为关系数据管理方面的主导者。不过,在最近几年对更加灵活和面向文档的数据结构的需求越来越大。这种数据结构的杰出例子就是 XML。

在许多关系数据库系统开始在其数据库中添加某种形式的 XML 支持时,IBM DB2 是唯一允许将 XML 原生地储存在数据库中的产品,不需要对 XML 的初始形式进行任何更改。这种技术称为 pureXML — 它允许 DB2 开发人员和 DBA 以 XML 数据和关系数据的形式操作报告,并且不对 XML 的纯度产生不良影响。

在本教程中中,您将开发一个 Python 脚本,它连接到美国人口普查局的 Web 站点,并下载一个包含关于国家、地区和州级别的人口数据的 CSV 文件 —— 包括 2000 年的人口普查结果,并且在后续的年份中该数据根据估算值浮动。您将学习如何处理该数据,即将它转换成 XML 文档。您并不导入这个大型文档然后使用 DB2 函数将其划分成单个的行,而是使用 Python 将该数据插入到 DB2 中,其中使用一个 XML 文档来储存 CSV 文件中对应的每个相关行。最后,您将创建一个命令行应用程序,它生成一些关于该数据的有用报告,这些报告根据人口从多到少的顺序显示州、地区或国家列表。

先决条件

要遵循本教程中的步骤,您需要安装以下软件:

  • IBM DB2 Express-C 9.5 或更新版本
  • Python Version 2.6 或 3.0 之前的任何版本

参考资料 部分提供这些软件的下载链接。本教程假设您使用 Microsoft Windows 操作系统,最好是 XP 或更新版本。为了安装 Python 和针对 Python 的 IBM DB2 扩展,您需要具有管理员权限。


创建数据库

在这个小节中,在创建一系列用于储存 XML 格式的人口普查数据的表之前,您将使用 DB2 Command Editor 实用程序创建一个新的 IBM DB2 数据库。您将创建这 3 个表:country、region 和 state。每个表将为表中的每个行储存一个唯一的 ID,以及储存一个用于保存人口普查数据的 XML 文档(在本教程的后面从美国人口普查局的 CSV 文件导入)。

创建数据库

让我们开始创建数据库。打开 DB2 Command Editor (Start>Programs>IBM DB2>[DB2 Instance Name]>Command Line Tools) 并输入以下命令:create database census using codeset UTF-8 territory US

完成该过程需要一两分钟,请耐心等待。完成之后,您将收到一条这样的响应消息:DB20000I The CREATE DATABASE command completed successfully

技巧:您可以在 Command Editor 中按 Ctrl+Enter 快速执行命令。

现在使用以下命令连接到新创建的人口普查数据库:connect to census

在这里,您还应该收到一条来自 DB2 服务器的响应消息:A JDBC connection to the target has succeeded

现在已经创建好数据库,您可以创建用于储存应用程序数据的表了。

创建数据库表

您将把人口数据装载到数据库并将其储存在 3 个独立的表中:country、region 和 state。现在,让我们通过 清单 1 创建这些表。

清单 1. 用于创建表的 DDL SQL 语句
create table country (
    id int not null generated by default as identity,
    data xml not null,
    primary key(id)
);

create table region (
    id int not null generated by default as identity,
    data xml not null,
    primary key(id)
);

create table state (
    id int not null generated by default as identity,
    data xml not null,
    primary key(id)
);

所有这些表都储存相同类型的数据 —— 每插入一个行时 DB2 自动生成的唯一标识符,以及用于为每个行储存一个 XML 文档的 XML 数据列。严格来说,您可以在这里仅使用一个表,然后在其上创建一个类型列来决定行是 country、region 还是 state,但是将数据储存在 3 个表中为以后的操作带来更多的灵活性。

当您执行以上的 SQL 语句时,DB2 将为每个表返回以下的响应消息:DB20000I。SQL 命令成功完成。

配置好数据库之后,您可以安装 Python 和针对 Python 的 ibm_db 扩展了。


安装和配置 Python

Python 是非常关注代码的可读性的高级编程语言。和许多其他缩进和编程风格由开发人员决定的编程语言不同,Python 要求您必须使用缩进来表示代码块(比如类、语句和循环)。Python 易于学习、生成的代码非常干净美观、适用于许多不同的平台,因此它是开发许多应用程序项目的不错选择。

关于 Python

尽管 Python 通常预安装在 Mac OS X 和 Linux® 操作系统上,但它并没有预安装在 Microsoft Windows 操作系统上。幸运的是,您可以从 Web 下载 Python 并将其安装到 Windows 操作系统上 —— 下一个小节将进行介绍。不过,在开始之前,您应该知道下载 Python for Windows 有许多可选的方式。

第一个选择是使用开源的官方二进制安装程序,可从 Python 的官方站点下载。这种方式提供最新的 Python 版本,并且是根据开源许可提供的。在本教程中,您将使用这个版本的 Python。

另外,商业性的 ActiveState Python 提供一些额外的资源来方便使用 Python 开发基于 Win32 API 的应用程序,这些资源包括完整的文档和其他 Python 扩展,包括针对 Windows 的扩展。

安装 Python

安装 Python 的第一步是从官方 Python Web 站点下载它(参考资料 部分提供一个链接)。在撰写本教程时,Python 的当前生产版本是 2.6.4 和 3.1.1。本教程假设您使用 2.6.* 版本的 Python。由于 3.0 以后的版本是非向后兼容的,因此我强烈建议您下载 3.0 之前的版本(2.x.x)。完成下载之后,将文件保存到硬盘中,然后打开 .msi 文件启动安装程序。

在安装程序启动时,它将询问您是供所有用户使用还是仅供个人使用(在 Windows Vista® 中没有这个选项)。使用默认选项 Install for all users 并按 Next 继续。现在,将询问您选择一个目标目录。默认的目录类似于 C:\Python26\;在这里也使用默认值并按 Next 继续。您将可以从这里定制 Python 安装,选择您需要安装的特性。默认情况下,将选择所有特性,因此使用默认设置并按 Next 开始安装过程。这个过程需要几分钟时间。安装完成之后,您将看到一个类似于 图 1 的窗口。

图 1. Completing the Python 2.6.4 Installer 窗口
Completing the Python 2.6.4 Installer 窗口的屏幕截图

按下 Finish 退出安装程序。在进入下一个步骤之前,您应该检查 Python 是否能够正常工作。您可以使用添加到 Windows 开始菜单栏的快捷方式,不过我建议您从命令提示符启动 Python,因为您将以这种方式运行在本教程后面创建的脚本。

首先,通过运行对话框打开 Windows 命令提示符窗口(Start>Run,然后输入 cmd),或导航到 Start>Programs>Accessories>Command Prompt。在命令提示符处输入命令:python

现在,您应该在 Python 提示符处,即 图 2 中的 >>>。(查看 图 2 的文本格式)。

图 2. Python 提示符
在命令提示符窗口中的 Python 提示符的屏幕截图

注意:如果您看到消息 python is not recognized as an internal or external command, operable program or batch file,这表明 Python 目录没有在 Windows Path 中。查看 参考资料 部分获得设置环境变量的信息。要退出 Python 提示符,输入以下命令:quit()

在 Python 提示符处输入了该命令之后,您将返回到 Windows 命令提示符。在下一个小节中,您将学习如何安装 ibm_db Python 扩展,该扩展允许您通过 Python 连接到 DB2 数据库。

安装 ibm_db Python 扩展

针对 Python 的 ibm_db 扩展允许您使用 Python 代码连接到 IBM DB2 数据库并与之交互。要安装该扩展,首先需要安装 easy_install 实用程序(setuptools)。导航到 setuptools package 页面(查看 参考资料 部分找到针对您的 Python 版本的文件,我在本教程中使用 2.6 版本)。将这个文件下载到硬盘中,下载完成之后打开它将 easy_install.exe 应用程序安装到 Python Scripts 目录中(通常为 C:\Python26\Scripts)。

安装 ibm_db 扩展是非常简单的。打开一个 Windows 命令提示符窗口(Start>Run>cmd)并输入以下命令,如果您将 Python 安装到其他目录,要相应地更改引用:C:\Python26\Scripts\easy_install ibm_db

这将自动地搜索、下载、提取和安装 ibm_db 扩展。完成之后,您将返回到 Windows 命令提示符,如 图 3 所示(查看 图 3 的文本格式)。

图 3. 成功安装 ibm_db 扩展
成功安装 ibm_db 扩展并显示 'Finished processing dependencies' 消息

接下来,您将通过连接到您在前面创建的 DB2 数据库来测试 ibm_db 扩展是否正常工作。

从 Python 连接到 DB2

创建了 DB2 数据库并安装和配置好 Python 和 ibm_db 扩展之后,您现在可以检查是否可以从 Python 连接到 DB2。打开 Windows 命令提示符并发出 python 命令来启动 Python 解释器。

在提示符处输入以下命令,以连接到 DB2 并计算 country 表中的行数。注意,这里包含的 Python 提示符 (>>> 和 ...) 仅用于演示目的,您不能将它们输入到解释器中。此外,确保使用您的实际 DB2 证书替换 清单 2 中的证书。

清单 2. 连接到 DB2 的 Python 代码
>>> import ibm_db
>>> conn =
 ibm_db.connect("DATABASE=census;HOSTNAME=localhost;PORT=50000;
PROTOCOL=TCPIP;UID=username;PWD=password;", "", "")
>>> sql = "SELECT COUNT(*) FROM country"
>>> stmt = ibm_db.exec_immediate(conn, sql)
>>> result = ibm_db.fetch_both(stmt)
>>> while result != False:
...     print "Count: ", result[0]
...     result = ibm_db.fetch_both(stmt)
...

在输入最后一行代码之后,按下 Enter 键将执行该代码。您将看到类似于 图 4 所示的结果 (Count: 0)。

图 4. DB2 连接测试的结果
DB2 连接测试的结果的屏幕截图

如果您不能从 Python 代码连接到 DB2,请检查 ibm_db 扩展是否正确安装,以及是否按照本教程前面的描述创建了 DB2 数据库。此外,还要检查您用于连接到 DB2 的证书是正确的。

设置好数据库并配置好 Python 之后,您现在可以进入本教程的主题了。在下一个小节中,您将从美国人口普查局下载、解析和转换 CSV 数据,并以 XML 格式将其保存在 DB2 数据库中。然后,您将学习如何从数据库读取这些数据并将其呈现给用户。


下载和转换 CSV 数据

在这个小节中,您将学习如何创建一个从美国人口普查局的 Web 站点下载 CSV 文件的 Python 脚本。接下来,您将处理该 CSV 数据并将其转换成可以储存在先前创建的 DB2 数据库中的 XML 数据。

在开始之前,您需要在硬盘的任意位置创建一个用于储存项目文件的目录。我将数据储存在 C:\pycensus 目录下,我建议您也使用该目录。

从美国人口普查局的 Web 站点下载 CSV 文件

美国人口普查局提供多种格式的数据供您下载。不幸的是,2000 年及往后年份的人口统计数据仅以 CSV 格式提供。但这并不构成问题,因为您可以使用 Python 从人口普查局的 Web 站点下载 CSV 文件,然后将其转换成可以储存在 DB2 pureXML 数据库中的 XML 数据。

您还可以选择将 Web 浏览器指向 CSV 文件项目文件夹的 URL。不过,在这里您通过构建 Python 脚本来完成该任务。在您的文本编辑器中,创建一个新文件并以 download.py 为名称将其保存在项目文件夹中(例如 C:\pycensus)。将 清单 3 中的代码添加到该文件中。

清单 3. download.py
import httplib
conn = httplib.HTTPConnection("www.census.gov")
conn.request("GET", "/popest/national/files/NST-EST2008-alldata.csv")
response = conn.getresponse()
f = open('data.csv', 'w')
f.write(response.read())
f.close()
conn.close()

在该脚本中,您使用 httplib 模块连接到 census.gov Web 站点,并发出请求所需的 CSV 文件的 GET 请求。接下来,您将获取响应并将其写到名为 data.csv 的文件中。要运行该脚本,打开 Windows 命令提示符并按照以下方式切换到项目目录:cd \pycensus

接下来,通过以下命令运行 Python 脚本:python download.py

在脚本运行完毕之后您将返回到命令提示符处。您可能会问 “为什么没有生成消息” —— 不用担心,这表明没有发生任何错误。在 Windows Explorer 浏览器中打开您的项目文件夹,现在您将注意到在 data.csv 文件夹下多了一个文件。如果您安装了 Microsoft Excel®,它就是这种文件类型的默认处理程序。打开该文件将生成类似于 图 5 的结果。

图 5. Microsoft Excel 中的 data.csv
Microsoft Excel 中的 data.csv 的屏幕截图

警告:不要在 Excel 中保存该文件,因为这样做会改变 CSV 文件的格式,Python 可能不能识别这种格式。如果 Excel 询问您是否保存文件,选择 No。如果意外保存了该文件,那么删除它并重新运行 download.py Python 脚本。在下一个小节中,您将学习如何获取这个 CSV 文件并将其转换成 XML。

将 CSV 数据转换成 XML 文档

要将 CSV 转换成 XML,您首先必须明白应该如何储存数据,是否分开储存不同的记录,并检查是否存在应该删除的无用记录。在您刚才下载的样例 CSV 文件中,您将注意到它包含 3 种类型的数据:1 行针对整个国家的数据;4 行针对地区 Northeast、Midwest、South 和 West 的数据、51 行针对美国 50 个州和哥伦比亚特区的数据,还有 1 行针对 Puerto Rico Commonwealth 的数据。该文件的第一行是一个标题行,用作列名。

您在本小节中创建的脚本将选择标题行,并使用该数据构成 XML 文档中的记录应该具有的每个元素的标记名。该脚本将根据前 4 列决定特定的行引用 country、region 还是 state,并相应地设置标记名以表明引用哪个 XML 文档。最后,该脚本将选择排除 Puerto Rico Commonwealth 记录,因为它包含不完整的数据。

在您的文本编辑器中,创建一个新的文件并以 convert.py 为名保存它。将 清单 4 中的代码添加到该文件中。

清单 4. convert.py
import csv

reader = csv.reader(open('data.csv'), delimiter=',', quoting=csv.QUOTE_NONE)

print "<data>"
for record in reader:
    if reader.line_num == 1:
        header = record
    else:
        innerXml = ""
        dontShow = False
        type = ""
        for i, field in enumerate(record):
            innerXml += "<%s>" % header[i].lower() + field + "</%s>" 
% header[i].lower()
            if i == 1 and field == "0":
                type = "country"
            elif type == "" and i == 3 and field == "0":
                type = "region"
            elif type == "" and i == 3 and field != "0":
                type = "state"

            if i == 1 and field == "X":
                dontShow = True

        if dontShow == False:
            xml = "<%s>" % type
            xml += innerXml
            xml += "</%s>" % type
            print xml
print "</data>"

在这个文件中,您使用 csv 库来读取 data.csv 文件。您以打开的 <data> 和关闭的 </data> XML 标记包围输入,因为仅生成一个文档输出。然后您将遍历 CSV 文件的每一行。如果当前的行是文件的第一行,就将该记录设置为标题。这在后面被用作脚本中的 country、region 或 state 记录中的每个字段的元素名。如果当前的行不是标题记录,您将遍历该记录中的每个列,并创建一个内部 XML 元素字符串,其名称来自标题记录。然后,检查处理的行是否引用 country、region 或 state,并将内部 XML 元素相应地包围在外部标记 <country><region><state> 中。最后,您将检查该记录是否在特定的字段中包含 X,如果是,将布尔指示器设置为 True,它将阻止将特定的行添加到 XML 文档中。运行该脚本的方式之一是发出命令:python convert.py

以这种方式运行该脚本将生成类似于 图 6 的结果。

图 6. convert.py 输出
convert.py 输出的屏幕截图,将数据信息显示为串联的 XML 文档

如您所见,该脚本直接在屏幕上显示数据。如果将数据保存在一个文件中,它的作用就更加大了。您不需要创建其他 Python 代码来完成该任务,仅需更改发出的命令,告诉命令提示符将输出保存到一个名为 data.xml 的文件中:python convert.py > data.xml

这将在项目目录中创建一个名为 data.xml 的新文件。如果您在一个能够读取和格式化 XML 的应用程序中(比如 Firefox)打开该文件,将看到类似于 图 7 的输出。

图 7. Mozilla Firefox 中的 XML 输出
Mozilla Firefox 中的 XML 输出的屏幕截图

以这种方式将数据储存在文件中之后,您可以使用一个 .del 文件和 IMPORT 命令将 XML 导入到 DB2 数据库中。不过,这将导致把所有 XML 数据储存在 DB2 表中的一个行中。现在,您可以使用 XQuery 来分开该数据并将它们储存在不同的行中。但是,由于您已经使用 Python 来创建了 XML 文档,因此在 convert.py 脚本本身中直接执行一系列 INSERT 语句要简单得多。在下一个小节中,您将修改 convert.py 脚本,从而让它完成该任务。


使用 Python 将 XML 保存到 DB2 中

您在前面学习了如何将来自美国人口普查局的 CSV 数据格式化为一个大型的 XML 文档。现在,您将学习如何将表示 country、regions 和 states 的行插入到 DB2 数据库中。在这个小节中对您在 上一小节 中创建的 convert.py 文件进行一些更改。

包含 ibm_db 库

您需要做的第一件事情是将 ibm_db 库包含到您的代码中。为此,将 covert.py 文件的第一行更改为:import csv, ibm_db

使用现在这个脚本时,多次运行它将导致重复插入每个行,从而产生大量重复数据。为了避免这个问题,在开始脚本时清除数据库表,从而使每次运行时都重新开始。将 清单 4 中的 import 语句添加到下面的 清单 5 中(即添加到 清单 4 中的 reader = csv.reader... 行的前面)。

清单 5. convert.py 节选 — 清除表
connString = "DATABASE=census;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;
UID=username;PWD=password;"
try:
    conn = ibm_db.connect(connString, "", "")
except:
    print "Could not connect to DB2: ", ibm_db.conn_errormsg()
else:
    print "Connected to DB2."

sql = "DELETE FROM country"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from country table: ", ibm_db.stmt_errormsg()
else:
    print "Country table emptied."

sql = "DELETE FROM region"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from region table: ", ibm_db.stmt_errormsg()
else:
    print "Region table emptied."

sql = "DELETE FROM state"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from state table: ", ibm_db.stmt_errormsg()
else:
    print "State table emptied."

您可能还记得在本教程 前面的小节 中用于连接到 DB2 数据库的代码,您还测试了到 DB2 的 Python 连接是可用的。这次,您将执行这些 SQL 语句 —— 分别从 country、region 和 state 表中删除所有数据。在每次删除完成之后,Python 将输出一条表示语句成功执行或出现错误的消息。如果发生错误,将向用户显示 DB2 错误消息,以便进行调试。

接下来,您需要删除两条打印语句,它们为您在 前面小节 中的大型文档输出外部 XML 声明。这些打印语句为:print "<data>"print "</data>"

第一条打印语句在 reader = csv.reader... 的下面,第二条在文件的最后一行代码中。

最后,您需要更改 convert.py 文件让它不为每行打印 XML 代码,而是将其保存为适当的 DB2 表中的 XML 文档。您已经创建了确定特定的行是否属于 country、region 或 state 并且为该行生成 XML 的代码;现在,您仅需创建一个相关的 INSERT 语句并执行它。

找到现在为 print xml 的代码行。您需要使用 清单 6 的代码替换该行。记住,Python 对代码缩进十分敏感,所以要在文本编辑器中确保代码的缩进是正确的。

清单 6. convert.py 节选 — 将行保存到 DB2 数据库
if type == "country":
    sql = "INSERT INTO country(data) VALUES('%s')" % xml
elif type == "region":
    sql = "INSERT INTO region(data) VALUES('%s')" % xml
elif type == "state":
    sql = "INSERT INTO state(data) VALUES('%s')" % xml

try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error adding row: ", ibm_db.stmt_errormsg()
else:
    print "Row added to %s table" % type

convert.py 文件的最终代码如 清单 7 所示。再次强调一下,缩进在 Python 中是非常重要的,因此要确保缩进正确,否则可能得到意外结果。

清单 7. convert.py
import csv, ibm_db

connString = "DATABASE=census;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=jjlennon;
PWD=DopGX240;"
try:
    conn = ibm_db.connect(connString, "", "")
except:
    print "Could not connect to DB2: ", ibm_db.conn_errormsg()
else:
    print "Connected to DB2."

sql = "DELETE FROM country"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from country table: ", ibm_db.stmt_errormsg()
else:
    print "Country table emptied."

sql = "DELETE FROM region"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from region table: ", ibm_db.stmt_errormsg()
else:
    print "Region table emptied."

sql = "DELETE FROM state"
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error deleting from state table: ", ibm_db.stmt_errormsg()
else:
    print "State table emptied."

reader = csv.reader(open('data.csv'), delimiter=',', quoting=csv.QUOTE_NONE)
for record in reader:
    if reader.line_num == 1:
        header = record
    else:
        innerXml = ""
        dontShow = False
        type = ""
        for i, field in enumerate(record):
            innerXml += "<%s>" % header[i].lower() + field + "</%s>" 
% header[i].lower()
            if i == 1 and field == "0":
                type = "country"
            elif type == "" and i == 3 and field == "0":
                type = "region"
            elif type == "" and i == 3 and field != "0":
                type = "state"

            if i == 1 and field == "X":
                dontShow = True
        if dontShow == False:
            xml = "<%s>" % type
            xml += innerXml
            xml += "</%s>" % type
            if type == "country":
                sql = "INSERT INTO country(data) VALUES('%s')" % xml
            elif type == "region":
                sql = "INSERT INTO region(data) VALUES('%s')" % xml
            elif type == "state":
                sql = "INSERT INTO state(data) VALUES('%s')" % xml
            try:
                stmt = ibm_db.exec_immediate(conn, sql)
            except:
                print "Error adding row: ", ibm_db.stmt_errormsg()
            else:
                print "Row added to %s table" % type

确保您已经保存了该文件并打开 Windows 命令提示符。更改项目目录并再次运行 convert.py 脚本,这次使用以下命令(不将输出导出到文件):python convert.py

您将看到连续出现的多条 “Row added to state table” 消息,如 图 8 所示。

图 8. 修改后的 convert.py 的输出
修改后的 convert.py 的输出的屏幕截图

在使用 Python 从 DB2 数据库读取该数据之前,打开 DB2 Command Editor 并查看该数据在数据库中的外观。确保您已经连接到 census 数据库(如果需要,发出命令 connect to census)并输入以下 SQL 语句:select * from state。这个查询将生成 51 个结果,如 图 9 所示。

图 9. Query Results 视图
Query Results 视图的屏幕截图,显示 XML 数据的条数

单击 Query Results 选项卡中的行旁边的 more (...) 按钮。这将打开 XML Document Viewer,它显示与特定的行相关联的 XML 文档。这类似于 图 10 所示。

图 10. XML 文档查看器
XML 文档查看器中的 Tree View 选项卡的屏幕截图

您可以执行任意类似的 SQL 语句从 country 和 region 表获取数据;您将从 country 表获取到 1 个行,从 region 表获取到 4 个行。

接下来,您将了解如何从 DB2 将该数据读取到 Python 并向用户呈现它。

使用 Python 从数据库读取 XML

在这个小节中,您将学习如何构建一个命令行 Python 应用程序,它将请求用户输入选择 3 个菜单选项之一。这些选项将允许用户查看根据 2000 年的人口普查进行排序的州、地区和国家列表。

您首先需要连接到 DB2 数据库、打印菜单选项列表并请求用户输入。创建一个新文件并命名为 read.py,然后将 清单 8 中的代码添加到该文件中。

清单 8. read.py 文件节选 — 开始
import ibm_db, locale, sys

locale.setlocale(locale.LC_ALL, '')

connString = "DATABASE=census;HOSTNAME=localhost;PORT=50000;
PROTOCOL=TCPIP;UID=username;PWD=password;"
try:
    conn = ibm_db.connect(connString, "", "")
except:
    print "Could not connect to DB2: ", ibm_db.conn_errormsg()
else:
    print "Connected to DB2."

print "To view population information, please select one of the following options:"
print "1.) List of states by population"
print "2.) List of regions by population"
print "3.) List of countries by population"
print "4.) Exit the application"

input = False
while input == False: 
    try:
        option = int(raw_input("Please enter a number from the options above to 
view that information: "))
        if option not in [1,2,3,4]:
            raise IOError('That is not a valid option!')
    except:
        print "That is an invalid option."
    else:
        input = True

清单 8 中,您首先导入 ibm_db 和本地位置(locale)库。需要使用本地位置库来格式化人口数量,从而使它的可读性更强(使用千分隔符)。您首先将本地位置设置为您的机器的默认值。接下来,在输出关于不同的菜单选项(将对用户可用)的信息之前连接到 DB2 数据库。

清单 8 中的代码的最后部分要求用户输入一个值,并验证该值是一个整数,它是 1、2、3 或 4 之一。如果提供的值不是这四个值之一,将继续要求输入一个值,直到该值有效为止。用户可以在任何时候通过选择 4 退出程序。

应用程序已经确定了用户想要查看的数据,接下来它必须构建一个适当的 SQL 语句来获取这些数据。清单 9 中的代码就是用来完成该任务的。

清单 9. read.py 节选 — 构建 SQL
selected = ""
if option == 1:
    sql = "select x.* from state s, xmltable('$d/state' passing s.data as \"d\"\
    columns \
    name varchar(50) path 'name', \
    pop int path 'census2000pop') as x \
    order by x.pop desc"
    selected = "state"
elif option == 2:
    sql = "select x.* from region r, xmltable('$d/region' passing r.data as \"d\"\
    columns \
    name varchar(50) path 'name', \
    pop int path 'census2000pop') as x \
    order by x.pop desc"
    selected = "region"
elif option == 3:
    sql = "select x.* from country c, xmltable('$d/country' passing c.data as \"d\"\
    columns \
    name varchar(50) path 'name', \
    pop int path 'census2000pop') as x \
    order by x.pop desc"
    selected = "country"
elif option == 4:
    sys.exit()

清单 9 中,if 代码块检查用户的输入选择是否为值 1、2、3 或 4。如果它检测到值介于 1 和 3 之间,那么将创建一个用于查看州、地区和国家的人口数据的 SQL 语句。如果检测到输入的值为 4,将退出程序。

该 SQL 语句对每个选项都是一样的,但它在每个实例中查找不同的表。它使用 XMLTABLE 函数来将表中的数据列中的 XML 元素映射到不同的关系列中。然后,它根据人口的值将数据从高到低排序。

该应用程序的最后部分是执行 SQL 语句并遍历结果集来生成结果表。清单 10 显示了该代码。

清单 10. read.py 节选 — 格式化结果
try:
    stmt = ibm_db.exec_immediate(conn, sql)
except:
    print "Error retrieving data: ", ibm_db.stmt_errormsg()
else:
    res = ibm_db.fetch_both(stmt)
    print ".----------------------------------------------,"
    print "|                                              |"
    print "|", ("%s LIST BY POPULATION" % selected.upper()).center(44), "|"
    print "|                                              |"
    print "|----------------------------------------------|"
    print "|", ("%s" % selected.upper()).center(21), " | ", "POPULATION".center(18), "|"
    print "|----------------------------------------------|"
    while res != False:
        print "|", res[0].ljust(21), " | ", locale.format("%d", res[1], grouping=True)
.rjust(18), "|"
        res = ibm_db.fetch_both(stmt)
    print "'----------------------------------------------'"

在该代码中,您执行由 清单 9 中的代码生成的 SQL 语句,然后生成一个整齐地格式化结果的表。在这个小节中,您使用一系列执行字符串操作(比如左对齐、居中和右对齐)的 Python 函数和千分隔符来让数据的可读性更强。

编写了从数据库读取数据的脚本之后,您可以执行它了。在 Windows 命令提示符处确保您位于项目目录中,然后使用以下命令启动程序:python read.py

当程序执行时,它将连接到 DB2 并显示以下菜单选项列表,您可以在应用程序中查看这些列表:

  1. List of states by population
  2. List of regions by population
  3. List of countries by population
  4. Exit the application

图 11 显示了这些菜单选项(查看 图 11 的文本格式)。

图 11. 应用程序菜单
包含四个选项的应用程序菜单的屏幕截图

尝试输入无效的菜单选项,比如字符串 hello。您将收到一个如 图 12 所示的错误消息,然后要求您再输入一个选项(查看 图 12 的文本格式)。

图 12. 无效菜单选项错误
无效菜单选项错误的屏幕截图

这次输入一个有效值。我选择选项 2 (List of regions by population)。这将生成一个如 图 13 所示的结果(查看 图 13 的文本格式)。

图 13. 地区人口数据
地区人口数据的屏幕截图

如您所见,该应用程序呈现一个带有地区列表的表,其中先显示人口最多的地区。对于其他两个选项,您将看到类似的结果,不同之处是选项 1 显示 51 个州,选项 3 显示 1 个国家。

请尝试查看不同的菜单选项,然后尝试改进改应用程序,比如添加一些选项或不同的数据视图。


结束语

在本教程中,您学习了如何创建包含原生 XML 数据列的表的 DB2 数据库。学习了如何通过 easy_install 实用程序安装 Python 和针对 Python 的 ibm_db 扩展。接着验证了能够从 Python 解释器与 DB2 数据库通信。然后开发了一个从美国人口普查局的 Web 站点下载人口数据的 Python 脚本,并使用它将 CSV 数据转换成 XML 格式的数据并将数据储存到 DB2 表中。最后,您创建了一个基本的命令行应用程序,它提供关于国家、地区和州的人口数据的表格形式的报告。

本教程提供的信息让您能够进一步提升自己的 Python 和 DB2 开发技能。


下载

描述名字大小
Python CSV 源代码python.csv.source.zip3KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Information Management, Open source, Web development
ArticleID=466472
ArticleTitle=使用 Python 和 pureXML 操作 CSV 数据
publish-date=02042010