Как получить полное содержимое XML или HTML элемента, используя ElementTree? - PullRequest
10 голосов
/ 19 декабря 2008

То есть весь текст и вложенные теги, без тега самого элемента?

Наличие

<p>blah <b>bleh</b> blih</p>

хочу

blah <b>bleh</b> blih

element.text возвращает «бла» и etree.tostring (element) возвращает:

<p>blah <b>bleh</b> blih</p>

Ответы [ 6 ]

11 голосов
/ 19 декабря 2008

ElementTree работает отлично, ответ нужно собрать самостоятельно. Как то так ...

"".join( [ "" if t.text is None else t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )

Спасибо JV amd PEZ за указание на ошибки.


Редактировать.

>>> import xml.etree.ElementTree as xml
>>> s= '<p>blah <b>bleh</b> blih</p>\n'
>>> t=xml.fromstring(s)
>>> "".join( [ t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )
'blah <b>bleh</b> blih'
>>> 

Хвост не нужен.

6 голосов
/ 19 декабря 2008

Это решение, которое я использовал в итоге:

def element_to_string(element):
    s = element.text or ""
    for sub_element in element:
        s += etree.tostring(sub_element)
    s += element.tail
    return s
3 голосов
/ 04 декабря 2015

Это хорошие ответы, которые отвечают на вопрос ОП, особенно если вопрос ограничен HTML. Но документы по своей сути беспорядочные, и глубину вложенности элементов обычно невозможно предсказать.

Для имитации getTextContent () в DOM вам придется использовать (очень) простой рекурсивный механизм.

Чтобы получить только голый текст:

def get_deep_text( element ):
    text = element.text or ''
    for subelement in element:
        text += get_deep_text( subelement )
    text += element.tail or ''
    return text
print( get_deep_text( element_of_interest ))

Чтобы получить все подробности о границах между необработанным текстом:

root_el_of_interest.element_count = 0
def get_deep_text_w_boundaries( element, depth = 0 ):
    root_el_of_interest.element_count += 1
    element_no = root_el_of_interest.element_count 
    indent = depth * '  '
    text1 = '%s(el %d - attribs: %s)\n' % ( indent, element_no, element.attrib, )
    text1 += '%s(el %d - text: |%s|)' % ( indent, element_no, element.text or '', )
    print( text1 )
    for subelement in element:
        get_deep_text_w_boundaries( subelement, depth + 1 )
    text2 = '%s(el %d - tail: |%s|)' % ( indent, element_no, element.tail or '', )
    print( text2 )
get_deep_text_w_boundaries( root_el_of_interest )

Пример вывода из одного пункта в документации LibreOffice Writer (файл .fodt):

(el 1 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'Standard'})
(el 1 - text: |Ci-après individuellement la "|)
  (el 2 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 2 - text: |Partie|)
  (el 2 - tail: |" et ensemble les "|)
  (el 3 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 3 - text: |Parties|)
  (el 3 - tail: |", |)
(el 1 - tail: |
   |)

Одним из моментов, связанных с беспорядком, является то, что не существует жесткого и быстрого правила о том, когда стиль текста указывает границу слова, а когда нет: верхний индекс, следующий за словом (без пробелов), означает отдельное слово во всех случаях. случаи, которые я могу себе представить. OTOH иногда вы можете найти, например, документ, в котором первая буква либо выделена жирным шрифтом по какой-либо причине, либо, возможно, использует другой стиль для первой буквы, чтобы представить ее в верхнем регистре, а не просто использовать обычный символ UC.

И, конечно, чем менее «англоцентрична» эта дискуссия, тем больше тонкостей и сложностей!

2 голосов
/ 19 декабря 2008

Я сомневаюсь, что ElementTree - то, что нужно для этого использовать. Но если у вас есть веские причины для его использования, возможно, вы можете попытаться удалить корневой тег из фрагмента:

 re.sub(r'(^<%s\b.*?>|</%s\b.*?>$)' % (element.tag, element.tag), '', ElementTree.tostring(element))
1 голос
/ 21 февраля 2018

Большинство ответов здесь основаны на синтаксическом анализаторе XML ElementTree, даже Ответ PEZ на основе регулярных выражений все еще частично зависит от ElementTree.

Все они хороши и подходят для большинства случаев использования, но ради полноты стоит отметить, что ElementTree.tostring(...) даст вам эквивалентный фрагмент, но не всегда идентичный исходной полезной нагрузке. Если по какой-то очень редкой причине вы хотите извлечь контент как есть, вы должны использовать чистое решение на основе регулярных выражений. В этом примере я использую решение на основе регулярных выражений.

0 голосов
/ 19 декабря 2008

Не знаю, может ли быть внешней библиотекой вариант, но в любом случае - если на странице есть один <p> с таким текстом, jQuery-решение будет:

alert($('p').html()); // returns blah <b>bleh</b> blih
...