Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用lxml高效地解析这个包含嵌套元素的巨大XML文件?_Python_Xml_Lxml_Iterparse - Fatal编程技术网

Python 如何使用lxml高效地解析这个包含嵌套元素的巨大XML文件?

Python 如何使用lxml高效地解析这个包含嵌套元素的巨大XML文件?,python,xml,lxml,iterparse,Python,Xml,Lxml,Iterparse,我尝试使用语法分析这个巨大的XML文档。虽然它在一个示例文件上运行良好,但在试图处理真实文件(约400 MB)时却阻塞了系统 我尝试从xml文件中调整代码(它以流式方式处理数据,而不是一次在内存中加载),但由于元素的嵌套性质,我在隔离数据集时遇到了问题。我以前处理过简单的XML文件,但不是像这样的内存密集型任务 这是正确的方法吗? 如何将库存和出版商ID与每本书关联?这就是我计划最终关联这两个表的方式 非常感谢您的反馈 book.xml <BookDatabase> <

我尝试使用语法分析这个巨大的XML文档。虽然它在一个示例文件上运行良好,但在试图处理真实文件(约400 MB)时却阻塞了系统

我尝试从xml文件中调整代码(它以流式方式处理数据,而不是一次在内存中加载),但由于元素的嵌套性质,我在隔离数据集时遇到了问题。我以前处理过简单的XML文件,但不是像这样的内存密集型任务

这是正确的方法吗? 如何将库存和出版商ID与每本书关联?这就是我计划最终关联这两个表的方式

非常感谢您的反馈

book.xml

<BookDatabase>
    <BookHeader>
        <Name>BookData</Name>
        <BookUniverse>All</BookUniverse>
        <AsOfDate>2010-05-02</AsOfDate>
        <Version>1.1</Version>
    </BookHeader>

    <InventoryBody>
        <Inventory ID="12">
            <PublisherClass ID="34">
                <Publisher>
                    <PublisherDetails>
                        <Name>Microsoft Press</Name>
                        <Type>Tech</Type>
                        <ID>7462</ID>
                    </PublisherDetails>
                </Publisher>
            </PublisherClass>
            <BookList>
                <Listing>
                    <BookListSummary>
                        <Date>2009-01-30</Date>
                    </BookListSummary>
                    <Book>
                        <BookDetail ID="67">
                            <BookName>Code Complete 2</BookName>
                            <Author>Steve McConnell</Author>
                            <Pages>960</Pages>
                            <ISBN>0735619670</ISBN>
                        </BookDetail>
                        <BookDetail ID="78">
                            <BookName>Application Architecture Guide 2</BookName>
                            <Author>Microsoft Team</Author>
                            <Pages>496</Pages>
                            <ISBN>073562710X</ISBN>
                        </BookDetail>
                    </Book>
                </Listing>
            </BookList>
        </Inventory>
        <Inventory ID="64">
            <PublisherClass ID="154">
                <Publisher>
                    <PublisherDetails>
                        <Name>O'Reilly Media</Name>
                        <Type>Tech</Type>
                        <ID>7484</ID>
                    </PublisherDetails>
                </Publisher>
            </PublisherClass>
            <BookList>
                <Listing>
                    <BookListSummary>
                        <Date>2009-03-30</Date>
                    </BookListSummary>
                    <Book>
                        <BookDetail ID="98">
                            <BookName>Head First Design Patterns</BookName>
                            <Author>Kathy Sierra</Author>
                            <Pages>688</Pages>
                            <ISBN>0596007124</ISBN>
                        </BookDetail>
                    </Book>
                </Listing>
            </BookList>
        </Inventory>
    </InventoryBody>
</BookDatabase>

因此,如果你想要快速而肮脏的东西,你只需要记住最后一个被解析的出版商,并将其分配给每个bookdetail,直到找到下一个PublisherDetails。在提取bookdetail后,向fast_iter2函数中添加如下内容:

        if bookdetail['element'] == "PublisherDetails" and bookdetail['ID'] is not None:
            CurrentPublisher = bookdetail
        if bookdetail['element'] == "BookDetail":
            bookdetail['PublisherID'] = CurrentPublisher['ID'].text

您可以尝试以下方法:

import MySQLdb
from lxml import etree
import config

def fast_iter(context, func, args=[], kwargs={}):
    # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    # Author: Liza Daly    
    for event, elem in context:
        func(elem, *args, **kwargs)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

def extract_paper_elements(element,cursor):
    pub={}        
    pub['InventoryID']=element.attrib['ID']
    try:
        pub['PublisherClassID']=element.xpath('PublisherClass/@ID')[0]
    except IndexError:
        pub['PublisherClassID']=None
    pub['PublisherClassID']=element.xpath('PublisherClass/@ID')[0]
    for key in ('Name','Type','ID'):
        try:
            pub[key]=element.xpath(
                'PublisherClass/Publisher/PublisherDetails/{k}/text()'.format(k=key))[0]
        except IndexError:
            pub[key]=None
    sql='''INSERT INTO Publishers (InventoryID, PublisherClassID, Name, Type, ID)
           VALUES (%s, %s, %s, %s, %s)
        '''
    args=[pub.get(key) for key in
          ('InventoryID', 'PublisherClassID', 'Name', 'Type', 'ID')]
    print(args)
    # cursor.execute(sql,args)
    for bookdetail in element.xpath('descendant::BookList/Listing/Book/BookDetail'):
        pub['BookDetailID']=bookdetail.attrib['ID']
        for key in ('BookName', 'Author', 'Pages', 'ISBN'):
            try:
                pub[key]=bookdetail.xpath('{k}/text()'.format(k=key))[0]
            except IndexError:
                pub[key]=None
        sql='''INSERT INTO Books
               (PublisherID, BookDetailID, Name, Author, Pages, ISBN)
               VALUES (%s, %s, %s, %s, %s, %s)
            '''           
        args=[pub.get(key) for key in
              ('ID', 'BookDetailID', 'BookName', 'Author', 'Pages', 'ISBN')]
        # cursor.execute(sql,args)
        print(args)


def main():
    context = etree.iterparse("book.xml", events=("end",), tag='Inventory')
    connection=MySQLdb.connect(
        host=config.HOST,user=config.USER,
        passwd=config.PASS,db=config.MYDB)
    cursor=connection.cursor()

    fast_iter(context,extract_paper_elements,args=(cursor,))

    cursor.close()
    connection.commit()
    connection.close()

if __name__ == '__main__':
    main()
  • 不要使用
    fast\u iter2
    。这条线将两条线分开 来自特定处理函数的有用实用程序 (
    提取纸张元素
    fast\u iter2
    将两者混合在一起 让你没有可重复的代码
  • 如果在
    etree.iterparse(“book.xml”)中设置
    标记
    参数, 事件=(“结束”,tag='Inventory')
    然后是您的处理函数
    extract\u paper\u elements
    只会看到
    Inventory
    elements
  • 给定一个Inventory元素,您可以使用
    xpath
    方法进行挖掘 向下并刮取所需的数据
  • args
    kwargs
    参数被添加到
    fast\u iter
    so
    cursor
    可以传递到
    提取纸张元素

  • 您可能希望尝试使用流解析器,一次只处理一个元素,而不是将整个内容加载到内存中并使用DOM。是的,我抛弃了我的DOM代码,尝试使用iterparse。这就完成了任务(内存方面),我正在尝试将每个数据集与存储在MySQL中的ID关联。同意goldsz…而且由于内存有限,您可能希望将关系存储到磁盘。临时数据库应该足够了。SQLite可能是一个快速的解决方案(虽然速度较慢)。您的逻辑将不得不维护更多的状态。您可能希望将每个类别的逻辑分解为不同的a函数。维护表示上次遇到的PublisherDetails的对象,然后遇到的每个BookDetails都与该发布者相关。感谢Yzmir,我最终将在MySQL中存储数据。goldsz,如果我创建一个空白列表,并用每个上下文的图书和出版商数据填充它,您认为这是一个好主意吗?在周日工作,尝试将其加载到MySQL中,以便明天生成一个可读的CSV。寻找一个快速解决方案-我最终会为未来探索一个有效的解决方案。谢谢你让我回到fast_iter。限制库存标签也很有意义!很快就会让你知道它是如何进行的…太棒了,它工作得很好!也非常感谢你的解释,我相信像我这样的新手会受益。哎呀,看来我的幸福是短暂的:(我得到了一个分段错误错误:堆栈跟踪:它发生在我的Mac和CITOS机器上。Python 2.7,帮助!”TythCo码:这个问题是在运行开始的时候发生的,还是在中间的时候发生的?我无法从堆栈跟踪中识别出问题。你认为这是内存问题吗?它在处理2个库存之后发生了。(每个都有大约100本书)。在不同的机器上试过,同样的问题。感谢goldsz,当unutbu让我选择fast_iter而不是fast_iter2时,他正在研究这个解决方案。非常感谢!
    Publishers
    InventoryID PublisherClassID Name            Type ID
    12          34               Microsoft Press Tech 7462
    64          154              O'Reilly Media  Tech 7484
    
    Books
    PublisherID BookDetailID Name                              Author           Pages ISBN
    7462        67           Code Complete 2                   Steve McConnell  960   0735619670
    7462        78           Application Architecture Guide 2  Microsoft Team   496   073562710X
    7484        98           Head First Design Patterns        Kathy Sierra     688   0596007124
    
            if bookdetail['element'] == "PublisherDetails" and bookdetail['ID'] is not None:
                CurrentPublisher = bookdetail
            if bookdetail['element'] == "BookDetail":
                bookdetail['PublisherID'] = CurrentPublisher['ID'].text
    
    import MySQLdb
    from lxml import etree
    import config
    
    def fast_iter(context, func, args=[], kwargs={}):
        # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
        # Author: Liza Daly    
        for event, elem in context:
            func(elem, *args, **kwargs)
            elem.clear()
            while elem.getprevious() is not None:
                del elem.getparent()[0]
        del context
    
    def extract_paper_elements(element,cursor):
        pub={}        
        pub['InventoryID']=element.attrib['ID']
        try:
            pub['PublisherClassID']=element.xpath('PublisherClass/@ID')[0]
        except IndexError:
            pub['PublisherClassID']=None
        pub['PublisherClassID']=element.xpath('PublisherClass/@ID')[0]
        for key in ('Name','Type','ID'):
            try:
                pub[key]=element.xpath(
                    'PublisherClass/Publisher/PublisherDetails/{k}/text()'.format(k=key))[0]
            except IndexError:
                pub[key]=None
        sql='''INSERT INTO Publishers (InventoryID, PublisherClassID, Name, Type, ID)
               VALUES (%s, %s, %s, %s, %s)
            '''
        args=[pub.get(key) for key in
              ('InventoryID', 'PublisherClassID', 'Name', 'Type', 'ID')]
        print(args)
        # cursor.execute(sql,args)
        for bookdetail in element.xpath('descendant::BookList/Listing/Book/BookDetail'):
            pub['BookDetailID']=bookdetail.attrib['ID']
            for key in ('BookName', 'Author', 'Pages', 'ISBN'):
                try:
                    pub[key]=bookdetail.xpath('{k}/text()'.format(k=key))[0]
                except IndexError:
                    pub[key]=None
            sql='''INSERT INTO Books
                   (PublisherID, BookDetailID, Name, Author, Pages, ISBN)
                   VALUES (%s, %s, %s, %s, %s, %s)
                '''           
            args=[pub.get(key) for key in
                  ('ID', 'BookDetailID', 'BookName', 'Author', 'Pages', 'ISBN')]
            # cursor.execute(sql,args)
            print(args)
    
    
    def main():
        context = etree.iterparse("book.xml", events=("end",), tag='Inventory')
        connection=MySQLdb.connect(
            host=config.HOST,user=config.USER,
            passwd=config.PASS,db=config.MYDB)
        cursor=connection.cursor()
    
        fast_iter(context,extract_paper_elements,args=(cursor,))
    
        cursor.close()
        connection.commit()
        connection.close()
    
    if __name__ == '__main__':
        main()