zoukankan      html  css  js  c++  java
  • 事件驱动解析

    有时我们需要的只是树内某个地方的一小部分,因此将整个树解析到内存中,全体遍历并进行相关操作造成的内存开销会很大
    因此,etree提供了两个事件驱动的解析器接口
    一个是在构建树时,生成解析器事件(iterparse)
    另一个根本不构建树,而是以类似SAX的方式调用目标对象的反馈方法

    some_file_like = BytesIO(b"<root><a>data</a></root>")
    for event, element in etree.iterparse(some_file_like):
        print("%s, %4s, %s" % (event, element.tag, element.text)
        
    '''
    输出:
    end,    a, data
    end, root, None
    '''

    默认情况下,iterparse()只在解析完元素时生成事件,但可以通过events关键字参数控制

    some_file_like = BytesIO(b"<root><a>data</a></root>")
    for event, element in etree.iterparse(some_file_like,events=("start", "end")):
        print("%5s, %4s, %s" % (event, element.tag, element.text))
        
    '''
    输出:
    start, root, None
    start,    a, data
      end,    a, data
      end, root, None
    '''  

    注意,在接收开始事件时,元素的文本、尾部和子元素还不一定存在,只有结束事件才能保证元素已被完全解析
    它还允许您.clear()或修改元素的内容以节省内存
    因此,如果您解析一个大的树并且希望保持内存使用量小,那么您应该清理树中不再需要的部分
    .clear()的keep_tail=True参数确保当前元素后面的(tail)文本内容不会被触摸
    强烈建议修改解析器可能尚未完全读取的任何内容

    some_file_like = BytesIO(b"<root><a><b>data</b></a><a><b/></a></root>")
    for event, element in etree.iterparse(some_file_like):
        if element.tag == 'b':
            print(element.text)
        elif element.tag == 'a':
            print("** cleaning up the subtree")
            element.clear(keep_tail=True)
    '''
    输出:  
    data
    ** cleaning up the subtree
    None
    ** cleaning up the subtree
    '''  

    iterparse()的一个非常重要的用例是解析生成的大型XML文件,例如数据库转储
    大多数情况下,这些XML格式只有一个主数据项元素挂在根节点的正下方,并且重复了数千次
    在这种情况下,最好让lxml.etree来构建树,并且只截取这一个元素,使用普通的树API来提取数据

    xml_file = BytesIO(b'''
        <root>
            <a><b>ABC</b><c>abc</c></a>
            <a><b>MORE DATA</b><c>more data</c></a>
            <a><b>XYZ</b><c>xyz</c></a>
        </root>''')
    
    for _, element in etree.iterparse(xml_file, tag='a'):
        print('%s -- %s' % (element.findtext('b'), element[1].text))
        element.clear(keep_tail=True)
    
    '''
    输出:  
    ABC -- abc
    MORE DATA -- more data
    XYZ -- xyz
    '''  

    如果出于某种原因根本不需要构建树,则可以使用lxml.etree的目标解析器接口
    它通过调用目标对象的方法创建类似SAX的事件。通过实现部分或全部这些方法,可以控制生成哪些事件

    class ParserTarget:
         events = []
         close_count = 0
         def start(self, tag, attrib):
             self.events.append(("start", tag, attrib))
         def close(self):
             events, self.events = self.events, []
             self.close_count += 1
             return events
    
    parser_target = ParserTarget()
    
    parser = etree.XMLParser(target=parser_target)
    events = etree.fromstring('<root test="true"/>', parser)
    
    print(parser_target.close_count) #输出:1
    
    for event in events:
         print('event: %s - tag: %s' % (event[0], event[1]))
         for attr, value in event[2].items():
             print(' * %s = %s' % (attr, value))
             
    '''
    输出:     
    event: start - tag: root
     * test = true
    ''' 

    可随时重用解析器及其目标,因此要确保.close()方法确实已将目标状态重置为可用(在出现错误时也是如此!)

    events = etree.fromstring('<root test="true"/>', parser)
    print(parser_target.close_count) #输出:2
    
    events = etree.fromstring('<root test="true"/>', parser)
    print(parser_target.close_count) #输出:3
    
    events = etree.fromstring('<root test="true"/>', parser)
    print(parser_target.close_count) #输出:4
    
    for event in events:
         print('event: %s - tag: %s' % (event[0], event[1]))
         for attr, value in event[2].items():
             print(' * %s = %s' % (attr, value))
             
    '''
    输出: 
    event: start - tag: root
     * test = true
    ''' 
  • 相关阅读:
    1837. Isenbaev's Number(floyd)
    1414. Astronomical Database(STL)
    1067. Disk Tree(字符串)
    1682. Crazy Professor(并查集)
    1650. Billionaires(线段树)
    1316. Electronic Auction(树状数组)
    1701. Ostap and Partners(并查集-关系)
    大数字运算——2、BigDecimal
    大数字运算——1、BigInteger
    java中的访问修饰符2
  • 原文地址:https://www.cnblogs.com/shiliye/p/11836148.html
Copyright © 2011-2022 走看看