在 Python 中将 CSV 数据转换为 XML

逗号分隔值 (CSV) 是一种广泛使用的数据存储格式。它成功地以行和列的形式以易于解析的格式存储数据。顾名思义,CSV 文件中的行由分隔符分隔,通常是换行符 (‘\n’)。行中的每个值均使用逗号 (,) 彼此分隔。使用 Microsoft Excel 打开 CSV 文件会以表格格式描绘数据,但也可以通过使用文本编辑器打开 CSV 文件来理解 CSV 格式。Python 中有一些库可用于解析 CSV 文件,但最常见的库是 Pandas 库。

如果您不熟悉 pandas 库,请查看有关 pandas 的教程

文本编辑器中 CSV 文件的表示形式

在上图中,我们可以看到第一行只是标题或列的标题。这些标题在 Python 中用作 Pandas 数据框的下标来调用整个列。

可扩展标记语言或 XML 是一种用于以结构化格式表示数据的标记语言。它使用“<>”字符中的标签,开始和结束标签代表数据。标签由标签内容中包含的数据的键/类型组成。标签的内容包括标签中键/类型的值。随着文章的进展,这一点将会更加清晰。XML 还提供样式选项,以精美地显示数据。XML 文件可以使用支持的浏览器打开,并且可以使用文本编辑器或专用 XML 编辑器进行编辑。

本文的主旨是编写一个程序,从 CSV 文件中读取数据并将其转换为结构化 XML 格式。XML 的标签将以 CSV 文件中的列名称命名。标签内容将包含 CSV 中的行值。上述 CSV 将用于转换为 XML 格式。给定的输入(以表格形式)和预期的输出(以 XML 形式)如下所示:

以表格形式输入 CSV 数据
<collection oldcars="Car Details">
<carid title="C001">
<company>Hyundai</company>
<model>Aura</model>
<releaseyear>2019</releaseyear>
<licenseno>GJ23BB8384</licenseno>
<color>White</color>
<kmstravelled>28000</kmstravelled>
</carid>
<carid title="C002">
<company>Maruti</company>
<model>Eeco</model>
<releaseyear>2001</releaseyear>
<licenseno>GJ15AM7634</licenseno>
<color>White</color>
<kmstravelled>102013</kmstravelled>
</carid>
<carid title="C003">
<company>Hyundai</company>
<model>Alcazar</model>
<releaseyear>2021</releaseyear>
<licenseno>GJ01KJ9845</licenseno>
<color>Red</color>
<kmstravelled>3401</kmstravelled>
</carid>
<carid title="C004">
<company>Honda</company>
<model>City</model>
<releaseyear>2007</releaseyear>
<licenseno>GJ06RE4198</licenseno>
<color>Black</color>
<kmstravelled>45000</kmstravelled>
</carid>
<carid title="C005">
<company>Mahindra</company>
<model>Bolero</model>
<releaseyear>2006</releaseyear>
<licenseno>GJ17OY8714</licenseno>
<color>Black</color>
<kmstravelled>129090</kmstravelled>
</carid>
</collection>

程序运行后的预期 XML 输出

将创建一个 Python 函数,该函数接受 CSV 文件的名称和路径以及输出 XML 文件的名称和路径的输入。剩下的工作将由代码完成。驱动程序将调用该函数,然后在浏览器中打开 XML 文件以检查输出。应该注意的是,这里没有将样式特征添加到 XML 结构中,而只是创建了一个 XML 文档树。

创建函数

该函数有两个输入:输入文件路径和输出文件路径。但是需要有一个错误检查器来确保提供给函数的输入准确且没有错误。因此,该函数所做的第一件事是检查给定的输入文件名是否是 CSV 文件以及给定的输出文件名是否是 XML 文件。以下代码演示了相同的内容:

1
2
3
4
5
6
7
8
import pandas as pd
def CSVtoXML(inputfile,outputfile):
    if not inputfile.lower().endswith('.csv'):
        print('Expected A CSV File')
        return 0
    if not outputfile.lower().endswith('.xml'):
        print('Expected a XML file')
        return 0

上面的代码要做的第一件事是导入 Pandas 模块。将 CSV 文件作为数据帧读取是非常有必要的。使用Python String 的endswith() 函数检查CSV 格式的输入文件和XML 格式的输出文件。文件始终以其扩展名结尾,在 CSV 的情况下为“.csv”,在 XML 的情况下为“.xml”。endswith() 函数检查给定输入的字符串的最后一个字符。如果两者匹配且相等,则返回 True,否则返回 False。

现在,需要建立一个 try-except 块以确保作为输入的给定 CSV 文件存在。如果未找到该文件,程序应返回 FileNotFoundError。拦截此错误时,程序应返回一条错误消息,将输入作为现有文件提供。以下代码执行相同的操作:

9
10
11
12
13
try:
    df=pd.read_csv(inputfile)
except FileNotFoundError:
    print('CSV file not found')
    return 0

上面的代码片段尝试将给定的 CSV 文件读取为 Pandas Dataframe 对象。如果文件不存在,pandas 将产生 FileNotFoundError。

从 Dataframe 创建 XML

现在 CSV 文件已成功读取为数据帧,代码将数据帧操作为字符串格式,该格式与实际的 XML 所需格式相匹配。以下代码演示了相同的内容:

14
15
16
17 号
18
19
20
21
22
23
24
25
26
27
28
    entireop='<collection oldcars="Car Details">\n'
    att=df.columns
    rowop=''
    for j in range(len(df)):
        for i in range(len(att)):
            if i==0:
                rowop=rowop+f'<{att[i]} title="{df[att[i]][j]}">\n'
            elif i==len(att)-1:
                rowop=rowop+f'<{att[i]}>{df[att[i]][j]}</{att[i]}>\n</{att[0]}>\n'
            else:
                rowop=rowop+f'<{att[i]}>{df[att[i]][j]}</{att[i]}>\n'
    entireop=entireop+rowop+'</collection>'
    with open(outputfile,'w') as f:
        f.write(entireop)
CSVtoXML('Car Details.csv','example.xml')

在上面的代码片段中,wholeop 变量包含整个 XML 输出的字符串,这是必需的。XML 必须始终使用描述 XML 文档树描述的数据的标签来声明。这里,标签被命名为<collection>。此外,数据的描述被指定为 oldcars,这意味着 XML 文档描述的汽车详细信息是旧车。

Dataframe 的列功能给出了一个包含 Dataframe 的所有列名称的列表作为输出。它用于存储每个列名称,稍后可以将它们用作 Dataframe 的下标来调用整个列。att 变量存储列列表。剩下的任务是遍历 Dataframe 中的所有行,为行列中的每个值获取单独的输入,使用列名称创建标签,并将标签内容作为从行中获取的值。

for 循环执行前面描述的任务。为了准确定位数据框中的特定值,需要精确的列号和行号。例如,汽车模型“Alcazar”位于第三行的第三列。所以它被称为Dataframe[2][2]。第一个下标是列号,第二个下标是行号。应该注意的是,Dataframe 遵循 0 索引;即Dataframe中的第一个元素是Dataframe[0][0]。调用 Dataframe[2][2] 中的值的一种更简单的方法是使用列名称作为列的下标。它与 Dataframe[‘model’][2] 相同。由于“model”值位于 att 列表中的第三个位置,因此 Dataframe 可以使用 att 列表轻松引用它。

这是在上面提供的 for 循环中完成的。XML 文档树还应该能够独立地唯一地标识每个数据对象。这就是每个数据对象的第一个标签(在本例中为 carid)配备有包含 carid 数据值的标题属性的原因。其余标签只是用 <> 括起来的列名称作为起始标签,用 </> 括起来作为结束标签。标签内容作为值放置在当前行号的列中。

创建整个 XML 树后,需要将其与之前创建的 <collection> 标记连接起来。第 25 行执行相同的操作,它将 fullop 与生成的 XML 文档树连接起来并关闭集合标记。此后,以写入模式打开输出文件,并将以字符串形式创建的 XML 文档树写入该文件。程序运行后产生以下输出:

程序运行后生成的 XML 输出
<collection oldcars="Car Details">
<carid title="C001">
<company>Hyundai</company>
<model>Aura</model>
<releaseyear>2019</releaseyear>
<licenseno>GJ23BB8384</licenseno>
<color>White</color>
<kmstravelled>28000</kmstravelled>
</carid>
<carid title="C002">
<company>Maruti</company>
<model>Eeco</model>
<releaseyear>2001</releaseyear>
<licenseno>GJ15AM7634</licenseno>
<color>White</color>
<kmstravelled>102013</kmstravelled>
</carid>
<carid title="C003">
<company>Hyundai</company>
<model>Alcazar</model>
<releaseyear>2021</releaseyear>
<licenseno>GJ01KJ9845</licenseno>
<color>Red</color>
<kmstravelled>3401</kmstravelled>
</carid>
<carid title="C004">
<company>Honda</company>
<model>City</model>
<releaseyear>2007</releaseyear>
<licenseno>GJ06RE4198</licenseno>
<color>Black</color>
<kmstravelled>45000</kmstravelled>
</carid>
<carid title="C005">
<company>Mahindra</company>
<model>Bolero</model>
<releaseyear>2006</releaseyear>
<licenseno>GJ17OY8714</licenseno>
<color>Black</color>
<kmstravelled>129090</kmstravelled>
</carid>
</collection>

最终的 XML 输出保存在 example.xml 文件中

该 XML 文件也可以在浏览器中打开。它将产生如下输出:

在浏览器中打开时的 XML 文件

Pandas 数据框转 XML 函数()

Pandas 还为 Dataframe 提供了一个功能,允许用户直接将 CSV 文件转换为 XML 文件。它提供了更准确的 XML 结构,并且生成的输出可以很容易地被浏览器解析。整个工作可以用两行代码完成:

1
2
df=pd.read_csv('Car Details.csv')
df.to_xml('example.xml')

它产生或多或少相同类型的输出。输出如下图所示:

Pandas To Xml 函数创建的 XML

另请阅读:Pandas DataFrame.to_xml – 将 DataFrame 渲染为 XML 文档

完整代码供参考

下面给出了定义的函数 CSVtoXML() 以供参考。它的时间复杂度为 O(c*r),其中 c 是 CSV 文件中的列数,r 是 CSV 文件中的行数。

import pandas as pd
def CSVtoXML(inputfile,outputfile):
    if not inputfile.lower().endswith('.csv'):
        print('Expected A CSV File')
        return 0
    if not outputfile.lower().endswith('.xml'):
        print('Expected a XML file')
        return 0
    try:
        df=pd.read_csv(inputfile)
    except FileNotFoundError:
        print('CSV file not found')
        return 0
    entireop='<collection oldcars="Car Details">\n'
    att=df.columns
    rowop=''
    for j in range(len(df)):
        for i in range(len(att)):
            if i==0:
                rowop=rowop+f'<{att[i]} title="{df[att[i]][j]}">\n'
            elif i==len(att)-1:
                rowop=rowop+f'<{att[i]}>{df[att[i]][j]}</{att[i]}>\n</{att[0]}>\n'
            else:
                rowop=rowop+f'<{att[i]}>{df[att[i]][j]}</{att[i]}>\n'
    entireop=entireop+rowop+'</collection>'
    with open(outputfile,'w') as f:
        f.write(entireop)
CSVtoXML('Car Details.csv','example.xml')

结论

XML 是一种标记语言,它以结构化格式为用户生成数据。如果为 XML 提供了样式属性,它还可以设计并生成漂亮的数据输出。CSV 是一种数据存储格式,它使用分隔符将行和列值彼此分隔。将 CSV 文件转换为 XML 文件相对容易。通常,列名被视为标签名称,行中的值被视为标签内容。它使用简单的字符串操作技术来创建 XML 文档根树,然后将其保存到 XML 文件。使用嵌套 for 循环创建函数可能会导致函数花费大量时间。使用 to_xml() 函数将以更标准的方式更快地完成相同的工作。

参考

1)堆栈溢出