2015-06-24 1 views
1

Как получить весь текст до элемент в etree, отделенный от текста после элемент?lxml etree получить весь текст перед элементом

from lxml import etree 

tree = etree.fromstring(''' 
    <a> 
     find 
     <b> 
      the 
     </b> 
     text 
     <dd></dd> 
     <c> 
      before 
     </c> 
     <dd></dd> 
     and after 
    </a> 
''') 

Что я хочу? В этом примере <dd> теги разделители для всех из них

for el in tree.findall('.//dd'): 

Я хотел бы иметь весь текст до и после них:

[ 
    { 
     el : <Element dd at 0xsomedistinctadress>, 
     before : 'find the text', 
     after : 'before and after' 
    }, 
    { 
     el : <Element dd at 0xsomeotherdistinctadress>, 
     before : 'find the text before', 
     after : 'and after' 
    } 
] 

Моя идея состояла в том, чтобы использовать какой-заполнителей в дерево, с которым я заменяю теги <dd>, а затем разрезаю строку на этом месте, но мне нужна переписка с фактическим элементом.

ответ

2

Там может быть более простой способ, но я хотел бы использовать следующие XPath выражения:

preceding-sibling::*/text()|preceding::text() 
following-sibling::*/text()|following::text() 

Пример реализации (определенно нарушающих DRY принцип):

def get_text_before(element): 
    for item in element.xpath("preceding-sibling::*/text()|preceding-sibling::text()"): 
     item = item.strip() 
     if item: 
      yield item 

def get_text_after(element): 
    for item in element.xpath("following-sibling::*/text()|following-sibling::text()"): 
     item = item.strip() 
     if item: 
      yield item 

for el in tree.findall('.//dd'): 
    before = " ".join(get_text_before(el)) 
    after = " ".join(get_text_after(el)) 

    print { 
     "el": el, 
     "before": before, 
     "after": after 
    } 

Печатает:

{'el': <Element dd at 0x10af81488>, 'after': 'before and after', 'before': 'find the text'} 
{'el': <Element dd at 0x10af81200>, 'after': 'and after', 'before': 'find the text before'}