2013-06-25 2 views
0

Мне нужно перечислить все элементы в моем элементе <product>, потому что элементы <product> являются переменными.Python xml: список всех элементов в элементе

XML файл:

<catalog> 
    <product> 
     <element1>text 1</element1> 
     <element2>text 2</element2> 
     <element..>text ..</element..> 
    </produc> 
</catalog> 

Python анализатор: Я использую fast_iter, потому что мой файл XML велик ...

import lxml.etree as etree 
import configs.application as configs 

myfile = configs.application.tmp + '/xml_hug_file.xml' 

def fast_iter(context, func, *args, **kwargs): 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     elem.clear() 
     while elem.getprevious() is not None: 
      del elem.getparent()[0] 
    del context 

def process_element(catalog): 
    print("List all element of <product>") 

context = etree.iterparse(myfile, tag='catalog', events = ('end',)) 
fast_iter(context, process_element) 
+2

У вас есть вопросы? –

+0

Как я могу перечислить все элементы в моем продукте? – Benabra

+0

Что вы подразумеваете под "* list *"? Вы имеете в виду распечатать их по стандарту? Вы имеете в виду создать «список», члены которого связаны с вашим ''? –

ответ

1
def process_element(catalog, *args, **kwargs): 
    for child in catalog.getchildren(): 
     print(child.text) 
1

Это решение моей проблемы:

def process_element(catalog): 
    for product in catalog.findall('product'): 
     for element in product.findall('*'): 
      print(element.tag) 
      print(element.text) 
1

Вы можете использовать XPath 'product/*[starts-with(local-name(),"element")]':


import lxml.etree as ET 
import io 

content = '''\ 
<catalog> 
    <product> 
     <element1>text 1</element1> 
     <element2>text 2</element2> 
     <element3>text ..</element3> 
    </product> 
</catalog>''' 

def fast_iter(context, func, *args, **kwargs): 
    """ 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
    Author: Liza Daly 
    See also http://effbot.org/zone/element-iterparse.htm 
    """ 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      while ancestor.getprevious() is not None: 
       del ancestor.getparent()[0] 
    del context 


def process_element(catalog): 
    for elt in catalog.xpath('product/*[starts-with(local-name(),"element")]'): 
     print(elt) 

context = ET.iterparse(io.BytesIO(content), tag='catalog', events = ('end',)) 
fast_iter(context, process_element) 

дает

<Element element1 at 0xb7449374> 
<Element element2 at 0xb744939c> 
<Element element3 at 0xb74493c4> 

Кстати, я сделал изменения в fast_iter Лиз Дейли, который будет удалять больше элементов, поскольку они становятся невостребованными. Это должно уменьшить требования к памяти при анализе больших XML-файлов.

Вот пример, который показывает, как модифицированный fast_iter выше удаляет больше элементов, чем оригинальный fast_iter:

import logging 
import textwrap 
import lxml.etree as ET 
import io 

logger = logging.getLogger(__name__) 
level = logging.INFO 
# level = logging.DEBUG # uncomment to see more debugging information 
logging.basicConfig(level=level) 

def fast_iter(context, func, *args, **kwargs): 
    """ 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
    Author: Liza Daly 
    See also http://effbot.org/zone/element-iterparse.htm 
    """ 
    for event, elem in context: 
     logger.debug('Processing {e}'.format(e=ET.tostring(elem))) 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     logger.debug('Clearing {e}'.format(e=ET.tostring(elem))) 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      logger.debug('Checking ancestor: {a}'.format(a=ancestor.tag)) 
      while ancestor.getprevious() is not None: 
       logger.info('Deleting {p}'.format(
        p=(ancestor.getparent()[0]).tag)) 
       del ancestor.getparent()[0] 
    del context 

def orig_fast_iter(context, func, *args, **kwargs): 
    for event, elem in context: 
     logger.debug('Processing {e}'.format(e=ET.tostring(elem))) 
     func(elem, *args, **kwargs) 
     logger.debug('Clearing {e}'.format(e=ET.tostring(elem))) 
     elem.clear() 
     while elem.getprevious() is not None: 
      logger.info('Deleting {p}'.format(
       p=(elem.getparent()[0]).tag))     
      del elem.getparent()[0] 
    del context 

def setup_ABC(): 
    content = textwrap.dedent('''\ 
     <root> 
     <A1> 
      <B1></B1> 
      <C>1<D1></D1></C> 
      <E1></E1> 
     </A1> 
     <A2> 
      <B2></B2> 
      <C>2<D></D></C> 
      <E2></E2> 
     </A2> 
     </root> 
     ''') 
    return content 

content = setup_ABC() 
context = ET.iterparse(io.BytesIO(content), events=('end',), tag='C') 
orig_fast_iter(context, lambda elem: None) 
# DEBUG:__main__:Deleting B1 
# DEBUG:__main__:Deleting B2 

print('-'*80) 
""" 
The improved fast_iter deletes A1. The original fast_iter does not. 
""" 
content = setup_ABC() 
context = ET.iterparse(io.BytesIO(content), events=('end',), tag='C') 
fast_iter(context, lambda elem: None) 
# DEBUG:__main__:Deleting B1 
# DEBUG:__main__:Deleting A1 
# DEBUG:__main__:Deleting B2 

Таким образом, вы видите, модифицированный fast_iter удается удалить A1 элемент, поскольку он не нужен к тому времени обрабатывается второй элемент C. В оригинале fast_iter удаляются только родители из C элементов (т. Е. B элементов). Вы могли бы представить, что такие вещи, как A1, могут быть довольно большими в большом XML-файле, и таких элементов может быть много. Таким образом, модифицированный fast_iter позволит осваивать много памяти, что оригинал fast_iter не освобождает.