将大型xml拆分为小块

2024-09-17 02:07:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我们希望处理大约6GB的大型xml文件

在这里,我们将大型xml读入dataframe,然后将其导出到csv文件 我们使用lxml和iterparse逐行读取xml并将其加载到dataframe中,但这个过程几乎需要6分钟

因此,我们决定将这个xml分割成小的块,比如每个1GB,然后并发处理它

您能推荐拆分这个大xml文件的最快方法吗

我已经尝试了linkhttps://gist.github.com/benallard/8042835,仅仅为了分割文件就几乎花费了8-10

我的xml的结构如下所示。在实际应用中,我们有将近200个标签,并且有将近100000条带有标签的记录

<?xml version="1.0" encoding="UTF-8"?>
<ACADEMICS>  
  <STUDENTS ASOF_DATE="11/21/2019" CREATE_DATE="11/22/2019" RECORDS="108881">      
    <STUDENT>      
      <NAME>JOHN</NAME>      
      <REGNUM>1000</REGNUM>      
      <COUNTRY>USA</COUNTRY>      
      <ID>JH1</ID>
      <SHORT_STD_DESC>JOHN IS A GOOD STUDENT</SHORT_STD_DESC>
    </STUDENT>
   <STUDENT>      
    <NAME>ADAM</NAME>      
    <REGNUM>1001</REGNUM>      
    <COUNTRY>FRANCE</COUNTRY>      
    <ID>AD2</ID>
    <SHORT_STD_DESC>ADAM IS A GOOD STUDENT</SHORT_STD_DESC>
  </STUDENT>
  <STUDENT>      
    <NAME>PETER</NAME>      
    <REGNUM>1003</REGNUM>      
    <COUNTRY>BELGIUM</COUNTRY>      
    <ID>PE5</ID>
    <SHORT_STD_DESC>PETER IS A GOOD STUDENT</SHORT_STD_DESC>
</STUDENT>
<STUDENT>      
    <NAME>ERIC</NAME>      
    <REGNUM>1006</REGNUM>      
    <COUNTRY>AUSTRALIA</COUNTRY>      
    <ID>ER7</ID>
    <SHORT_STD_DESC>ERIC IS A GOOD STUDENT</SHORT_STD_DESC>
</STUDENT>
<STUDENT>      
    <NAME>NICHOLAS</NAME>      
    <REGNUM>1009</REGNUM>      
    <COUNTRY>GREECE</COUNTRY>      
    <ID>NI8</ID>
    <SHORT_STD_DESC>NICHOLAS IS A GOOD STUDENT</SHORT_STD_DESC>
</STUDENT>


Tags: 文件nameiddataframedateis标签xml
1条回答
网友
1楼 · 发布于 2024-09-17 02:07:15

当我们想象一个最小解析器时,在读取XML文件时,我们只需要对几个事件做出反应:

  • 遇到一个开头<STUDENT>:准备一个新列表,这样我们就可以存储我们将看到的各种值
  • 遇到开口<NAME><REGNUM>等:找出此属性值应该放入哪个插槽(“当前”插槽)
  • 遇到一段文本:如果此文本属于我们关心的属性,请将其写入当前插槽
  • 遇到结尾</NAME></REGNUM>等:请注意,接下来出现的任何文本都不有趣,应该忽略
  • 遇到了一个结束</STUDENT>:我们已经完成了对当前学生的处理,可以输出我们收集的所有数据

考虑到这一点,我们可以创建一个SAX事件处理程序来实现这一想法:

from xml.sax.handler import ContentHandler

class StudentReader(ContentHandler):
    def __init__(self, callback=None):
        self.column_order = 'ID,NAME,REGNUM,COUNTRY,SHORT_STD_DESC'
        self.current_student = None
        self.current_idx = None
        self.mapping = {key: idx for idx, key in enumerate(self.column_order.split(','))}
        self.num_cols = len(self.mapping)
        self.callback = callback

    def startElement(self, tag, attrs):
        if tag == 'STUDENT':
            # new student with correct number of columns
            self.current_student = [''] * self.num_cols
        elif tag in self.mapping:
            # which column are we writing to?
            self.current_idx = self.mapping[tag]
        else:
            self.current_idx = None

    def endElement(self, tag):
        if tag == 'STUDENT':
            if self.callback is not None:
                # when we have a callback, call it
                self.callback(self.current_student)
            else:
                # without a callback, just print to console (for debugging)
                print(self.current_student)
        elif tag in self.mapping:
            self.current_idx = None

    def characters(self, data):
        if self.current_idx is not None:
            self.current_student[self.current_idx] += data

无需保留任何其他内容,无需构建树,我们可以在读取输入XML时执行此操作。这将非常快,并且使用的内存非常少

现在我们可以创建一个SAX解析器并为其提供一个StudentReader实例:

import xml.sax

handler = StudentReader()
xml.sax.parse('data.xml', handler)

…将列表打印到控制台:

['JH1', 'JOHN', '1000', 'USA', 'JOHN IS A GOOD STUDENT']
['AD2', 'ADAM', '1001', 'FRANCE', 'ADAM IS A GOOD STUDENT']
['PE5', 'PETER', '1003', 'BELGIUM', 'PETER IS A GOOD STUDENT']
['ER7', 'ERIC', '1006', 'AUSTRALIA', 'ERIC IS A GOOD STUDENT']
['NI8', 'NICHOLAS', '1009', 'GREECE', 'NICHOLAS IS A GOOD STUDENT']

例如,将数据写入CSV文件可能更有趣

这就是我们的StudentReader中的callback参数的作用-我们可以将这些列表直接传递给CSV编写器,这样它就可以在处理输入文件时编写输出文件

import csv
import xml.sax

with open('output.csv', 'w', encoding='utf8', newline='') as fp:
    writer = csv.writer(fp, delimiter=';')

    handler = StudentReader(writer.writerow)

    xml.sax.parse('data.xml', handler)

当然,您也可以在回调中使用数据库命令,或者您需要的任何命令

相关问题 更多 >