python - 使用 PYTHON 将 CSV 文件转换为 XML 文件

标签 python xml csv

我想用 python 将 csv 文件转换为 xml 文件。我想将 csv 文件中的相同 id 分组在一起,并将 csv 转换为 xml(请参阅所需的输出)。它比看起来有点复杂,包括缩进、循环和将 csv 分组为 xml。感谢所有帮助。

My CSV file:

id,x1,y1,z1,x2,y2,z2,c1,R
a1,1.3,2.1,3.6,4.5,5.1,6.8,B,7.3
b2,1.1,2.1,3.1,4.1,5.1,6.1,G,7.1
c1,2.1,3.1,4.1,5.1,2.1,7.1,G,8.1
a1,2.2,3.2,4.2,5.2,6.2,7.2,S,8.2
b2,4.1,5.1,2.1,7.1,8.1,9.1,S,2.5
b2,3.6,4.5,5.1,6.3,7.4,8.2,G,3.1
c2,6.1,7.1,8.1,9.1,2.1,11.1,S,3.2
c1,1.5,1.5,1.5,1.5,1.5,1.5,A,1.5


my code:

import itertools
import csv
import os

csvFile = r'C:\Users\Desktop\test XML\csvfile.csv'
xmlFile = r'C:\Users\Desktop\test XML\myData.xml'

csvData = csv.reader(open(csvFile))
xmlData = open(xmlFile, 'w')
xmlData.write('<?xml version="1.0" encoding="UTF-8"?>' + "\n" +'<Roughness-Profiles xmlns="http://WKI/Roughness-Profiles/1">' + "\n" )
xmlData.write(' '+'<Roughness-Profile>' + "\n")

rowNum = 0
for row in csvData:
    if rowNum == 0:
        tags = row
        # replace spaces w/ underscores in tag names
        for i in range(len(tags)):
            tags[i] = tags[i].replace(' ', '_')
    else: 
        xmlData.write('  '+'<surfaces>' +"\n"+'   '+'<surface>' + "\n")
        for i in range (len(tags)):
            xmlData.write('    ' +'<' + tags[i] + '>' \
                      + row[i] + '</' + tags[i] + '>' + "\n")

        xmlData.write('   '+'</surface>' + "\n" + '  '+'</surfaces>' + "\n" + ' '+'</Roughness-Profile>' + "\n")

    rowNum +=1

xmlData.write('</Roughness-Profiles>' + "\n")
xmlData.close()

我的 xml 输出:

<?xml version="1.0" encoding="UTF-8"?>
<Roughness-Profiles xmlns="http://WKI/Roughness-Profiles/1">
 <Roughness-Profile>
  <surfaces>
   <surface>
    <id>a1</id>
    <x1>1.3</x1>
    <y1>2.1</y1>
    <z1>3.6</z1>
    <x2>4.5</x2>
    <y2>5.1</y2>
    <z2>6.8</z2>
    <c1>B</c1>
    <R>7.3</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>b2</id>
    <x1>1.1</x1>
    <y1>2.1</y1>
    <z1>3.1</z1>
    <x2>4.1</x2>
    <y2>5.1</y2>
    <z2>6.1</z2>
    <c1>G</c1>
    <R>7.1</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>c1</id>
    <x1>2.1</x1>
    <y1>3.1</y1>
    <z1>4.1</z1>
    <x2>5.1</x2>
    <y2>2.1</y2>
    <z2>7.1</z2>
    <c1>G</c1>
    <R>8.1</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>a1</id>
    <x1>2.2</x1>
    <y1>3.2</y1>
    <z1>4.2</z1>
    <x2>5.2</x2>
    <y2>6.2</y2>
    <z2>7.2</z2>
    <c1>S</c1>
    <R>8.2</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>b2</id>
    <x1>4.1</x1>
    <y1>5.1</y1>
    <z1>2.1</z1>
    <x2>7.1</x2>
    <y2>8.1</y2>
    <z2>9.1</z2>
    <c1>S</c1>
    <R>2.5</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>b2</id>
    <x1>3.6</x1>
    <y1>4.5</y1>
    <z1>5.1</z1>
    <x2>6.3</x2>
    <y2>7.4</y2>
    <z2>8.2</z2>
    <c1>G</c1>
    <R>3.1</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>c2</id>
    <x1>6.1</x1>
    <y1>7.1</y1>
    <z1>8.1</z1>
    <x2>9.1</x2>
    <y2>2.1</y2>
    <z2>11.1</z2>
    <c1>S</c1>
    <R>3.2</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
  <surfaces>
   <surface>
    <id>c1</id>
    <x1>1.5</x1>
    <y1>1.5</y1>
    <z1>1.5</z1>
    <x2>1.5</x2>
    <y2>1.5</y2>
    <z2>1.5</z2>
    <c1>A</c1>
    <R>1.5</R>
   </surface>
  </surfaces>
 </Roughness-Profile>
</Roughness-Profiles>

期望的输出应该是:

<?xml version="1.0" encoding="UTF-8"?>
<R-Profiles xmlns="http://WKI/R-Profiles/1">
 <R-Profile>
  <id>a1</id>
  <surfaces>
   <surface>
    <x1>1.3</x1>
    <y1>2.1</y1>
    <z1>3.6</z1>
    <x2>4.5</x2>
    <y2>5.1</y2>
    <z2>6.8</z2>
    <c1>B</c1>
    <R>7.3</R>
   </surface>
   <surface>
    <x1>2.2</x1>
    <y1>3.2</y1>
    <z1>4.2</z1>
    <x2>5.2</x2>
    <y2>6.2</y2>
    <z2>7.2</z2>
    <c1>S</c1>
    <R>8.2</R>
   </surface>
    </surfaces>
 </R-Profile>
 <R-Profile>
  <id>b2</id>
  <surfaces>
   <surface>
    <x1>1.1</x1>
    <y1>2.1</y1>
    <z1>3.1</z1>
    <x2>4.1</x2>
    <y2>5.1</y2>
    <z2>6.1</z2>
    <c1>G</c1>
    <R>7.1</R>
   </surface>
   <surface>
    <x1>4.1</x1>
    <y1>5.1</y1>
    <z1>2.1</z1>
    <x2>7.1</x2>
    <y2>8.1</y2>
    <z2>9.1</z2>
    <c1>S</c1>
    <R>2.5</R>
   </surface>
   <surface>
    <x1>3.6</x1>
    <y1>4.5</y1>
    <z1>5.1</z1>
    <x2>6.3</x2>
    <y2>7.4</y2>
    <z2>8.2</z2>
    <c1>G</c1>
    <R>3.1</R>
   </surface>
    </surfaces>
 </R-Profile>
 <R-Profile>
  <id>c1</id>
  <surfaces>
   <surface>
    <x1>2.1</x1>
    <y1>3.1</y1>
    <z1>4.1</z1>
    <x2>5.1</x2>
    <y2>2.1</y2>
    <z2>7.1</z2>
    <c1>G</c1>
    <R>8.1</R>
   </surface>
   <surface>
    <x1>1.5</x1>
    <y1>1.5</y1>
    <z1>1.5</z1>
    <x2>1.5</x2>
    <y2>1.5</y2>
    <z2>1.5</z2>
    <c1>A</c1>
    <R>1.5</R>
   </surface>
   </surfaces>
 </R-Profile>
 <R-Profile>
  <id>c2</id>
  <surfaces>
   <surface>
    <x1>6.1</x1>
    <y1>7.1</y1>
    <z1>8.1</z1>
    <x2>9.1</x2>
    <y2>2.1</y2>
    <z2>11.1</z2>
    <c1>S</c1>
    <R>3.2</R>
   </surface>
  </surfaces>
 </R-Profile>
</R-Profiles>

最佳答案

我会做一些与@Parfait建议非常相似的事情;使用csv.DictReaderlxml创建 XML。

但是,这个答案缺少一些东西; surface 元素不按 id 分组。

如果我需要在转换期间对 XML 进行分组,我首先想到的是 XSLT。

一旦掌握了窍门,使用 XSLT 进行分组就很容易了;特别是 2.0 或更高。不幸的是 lxml 仅支持 XSLT 1.0。在1.0中你需要使用Muenchian Grouping .

下面是创建中间 XML 并使用 XSLT 对其进行转换的完整示例。

CSV 输入 (test.csv)

id,x1,y1,z1,x2,y2,z2,c1,R
a1,1.3,2.1,3.6,4.5,5.1,6.8,B,7.3
b2,1.1,2.1,3.1,4.1,5.1,6.1,G,7.1
c1,2.1,3.1,4.1,5.1,2.1,7.1,G,8.1
a1,2.2,3.2,4.2,5.2,6.2,7.2,S,8.2
b2,4.1,5.1,2.1,7.1,8.1,9.1,S,2.5
b2,3.6,4.5,5.1,6.3,7.4,8.2,G,3.1
c2,6.1,7.1,8.1,9.1,2.1,11.1,S,3.2
c1,1.5,1.5,1.5,1.5,1.5,1.5,A,1.5

XSLT 1.0(测试.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:rp="http://WKI/Roughness-Profiles/1">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="surface" match="rp:surface" use="rp:id"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each select="rp:surface[count(.|key('surface',rp:id)[1])=1]">
        <xsl:element name="Roughness-Profile" namespace="http://WKI/Roughness-Profiles/1">
          <xsl:copy-of select="rp:id"/>
          <xsl:element name="surfaces" namespace="http://WKI/Roughness-Profiles/1">
            <xsl:apply-templates select="key('surface',rp:id)"/>
          </xsl:element>
        </xsl:element>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="rp:id"/>

</xsl:stylesheet>

Python

import csv
import lxml.etree as etree

# INITIALIZING XML FILE WITH ROOT IN PROPER NAMESPACE
nsmap = {None: "http://WKI/Roughness-Profiles/1"}
root = etree.Element('Roughness-Profiles', nsmap=nsmap)

# READING CSV FILE
with open("test.csv") as f:
    reader = csv.DictReader(f)

    # WRITE INITIAL XML NODES
    for row in reader:
        surface_elem = etree.SubElement(root, "surface", nsmap=nsmap)
        for elem_name, elem_value in row.items():
            etree.SubElement(surface_elem, elem_name.strip(), nsmap=nsmap).text = str(elem_value)

# PARSE XSLT AND CREATE TRANSFORMER
xslt_root = etree.parse("test.xsl")
transform = etree.XSLT(xslt_root)

# TRANSFORM
#  (Note the weird use of tostring/fromstring. This was used so
#   namespaces in the XSLT would work the way they're supposed to.)
final_xml = transform(etree.fromstring(etree.tostring(root)))

# WRITE OUTPUT TO FILE
final_xml.write_output("test.xml")

XML 输出 (test.xml)

<?xml version="1.0"?>
<Roughness-Profiles xmlns="http://WKI/Roughness-Profiles/1">
  <Roughness-Profile>
    <id>a1</id>
    <surfaces>
      <surface>
        <x1>1.3</x1>
        <y1>2.1</y1>
        <z1>3.6</z1>
        <x2>4.5</x2>
        <y2>5.1</y2>
        <z2>6.8</z2>
        <c1>B</c1>
        <R>7.3</R>
      </surface>
      <surface>
        <x1>2.2</x1>
        <y1>3.2</y1>
        <z1>4.2</z1>
        <x2>5.2</x2>
        <y2>6.2</y2>
        <z2>7.2</z2>
        <c1>S</c1>
        <R>8.2</R>
      </surface>
    </surfaces>
  </Roughness-Profile>
  <Roughness-Profile>
    <id>b2</id>
    <surfaces>
      <surface>
        <x1>1.1</x1>
        <y1>2.1</y1>
        <z1>3.1</z1>
        <x2>4.1</x2>
        <y2>5.1</y2>
        <z2>6.1</z2>
        <c1>G</c1>
        <R>7.1</R>
      </surface>
      <surface>
        <x1>4.1</x1>
        <y1>5.1</y1>
        <z1>2.1</z1>
        <x2>7.1</x2>
        <y2>8.1</y2>
        <z2>9.1</z2>
        <c1>S</c1>
        <R>2.5</R>
      </surface>
      <surface>
        <x1>3.6</x1>
        <y1>4.5</y1>
        <z1>5.1</z1>
        <x2>6.3</x2>
        <y2>7.4</y2>
        <z2>8.2</z2>
        <c1>G</c1>
        <R>3.1</R>
      </surface>
    </surfaces>
  </Roughness-Profile>
  <Roughness-Profile>
    <id>c1</id>
    <surfaces>
      <surface>
        <x1>2.1</x1>
        <y1>3.1</y1>
        <z1>4.1</z1>
        <x2>5.1</x2>
        <y2>2.1</y2>
        <z2>7.1</z2>
        <c1>G</c1>
        <R>8.1</R>
      </surface>
      <surface>
        <x1>1.5</x1>
        <y1>1.5</y1>
        <z1>1.5</z1>
        <x2>1.5</x2>
        <y2>1.5</y2>
        <z2>1.5</z2>
        <c1>A</c1>
        <R>1.5</R>
      </surface>
    </surfaces>
  </Roughness-Profile>
  <Roughness-Profile>
    <id>c2</id>
    <surfaces>
      <surface>
        <x1>6.1</x1>
        <y1>7.1</y1>
        <z1>8.1</z1>
        <x2>9.1</x2>
        <y2>2.1</y2>
        <z2>11.1</z2>
        <c1>S</c1>
        <R>3.2</R>
      </surface>
    </surfaces>
  </Roughness-Profile>
</Roughness-Profiles>

关于python - 使用 PYTHON 将 CSV 文件转换为 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55503639/

相关文章:

python - 返回 OSError 异常类的子类实例的逻辑在哪里?

python - 如何使用启用了自定义 Fips 的 Openssl 编译 Python 3.6?

java - 在 Java 中将 LinkedIn XML 数据转换为 JSON

xml - JSP 与 Facelets 作为 JSF 的 View 技术

excel - 在 Excel 中导入 CSV 美国格式的数字并进行本地化?

python - 在 Python 中从 csv 文件的某一行进行迭代

Python:如何从 gzip 压缩中流式传输/管道传输数据?

隐藏在底部栏下方的Android float 操作栏

c# - 使用 ado.net 和 c# 连接 .csv 文件

python - 如何将两个 JSON 文件与 pandas 合并