То есть весь текст и вложенные теги без тега самого элемента?
Имея
<p>blah <b>bleh</b> blih</p>
я хочу
blah <b>bleh</b> blih
element.text возвращает "blah", а etree.tostring (element) возвращает:
<p>blah <b>bleh</b> blih</p>






ElementTree работает отлично, ответ нужно собрать самостоятельно. Что-то вроде этого...
"".join( [ "" if t.text is None else t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )
Спасибо СП 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'
>>>
Хвост не нужен.
Я делаю что-то похожее на это, но с интересом. Вам действительно не хватает хвоста.
Хвост - это лишний пробел после закрывающего тега конструкции.
Не знаю, может ли внешняя библиотека быть вариантом, но в любом случае - если на странице есть один <p> с этим текстом, jQuery-решение будет:
alert($('p').html()); // returns blah <b>bleh</b> blih
Я сомневаюсь, что для этого можно использовать ElementTree. Но если у вас есть веские причины для его использования, возможно, вы могли бы попробовать удалить корневой тег из фрагмента:
re.sub(r'(^<%s\b.*?>|</%s\b.*?>$)' % (element.tag, element.tag), '', ElementTree.tostring(element))
Это решение, которое я в итоге использовал:
def element_to_string(element):
s = element.text or ""
for sub_element in element:
s += etree.tostring(sub_element)
s += element.tail
return s
Это не сработает, если нет текста или хвоста, не так ли?
PEZ, да, он не работает, когда нет текста, просто нашел его, запустив мой код, и исправил. У меня много примеров отсутствия хвоста, и это не подводит меня. Не знаю почему.
Просто придирка: + = на струнах менее эффективен. Лучше всего собрать список строк и присоединить к нему "." В конце.
Вы можете выполнить рекурсию и снова вызвать element_to_string для подэлемента, чтобы захватить весь текст, то есть for sub_element in element: s += element_to_string(sub_element).
Это хорошие ответы, которые отвечают на вопрос OP, особенно если вопрос ограничен 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.
И, конечно же, чем менее «англо-центричным» эта дискуссия, тем больше тонкостей и сложностей!
Большинство ответов здесь основаны на анализаторе XML ElementTree, даже Ответ на основе регулярных выражений PEZ по-прежнему частично полагается на ElementTree.
Все они хороши и подходят для большинства случаев использования, но для полноты картины стоит отметить, что ElementTree.tostring(...) предоставит вам эквивалентный фрагмент, но не всегда идентичный исходной полезной нагрузке. Если по какой-то очень редкой причине вы хотите извлечь контент как есть, вам нужно использовать решение на основе чисто регулярных выражений. Этот пример - это то, как я использую решение на основе регулярных выражений.
Этот ответ немного изменен из ответа Пупено. Здесь я добавил тип кодировки в «tostring». На этот вопрос у меня ушло много часов. Надеюсь, это небольшое исправление поможет другим.
def element_to_string(element):
s = element.text or ""
for sub_element in element:
s += ElementTree.tostring(sub_element, encoding='unicode')
s += element.tail
return s
Просто указываю на опечатку - имя метода - «финал», которое, я думаю, должно было быть «findall». Даже если используется findall, это приводит к этому pastebin.com/f6de9a841. Пожалуйста, измените свой ответ.