如何使用ElementTree获取元素的完整XML或HTML内容?

时间:2008-12-19 10:33:52

标签: python xml api elementtree

即所有文本和子标签,没有元素本身的标记?

具有

<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>

7 个答案:

答案 0 :(得分:11)

ElementTree完美无缺,你必须自己组装答案。像这样......

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

感谢JV和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'
>>> 

不需要尾巴。

答案 1 :(得分:6)

这是我最终使用的解决方案:

def element_to_string(element):
    s = element.text or ""
    for sub_element in element:
        s += etree.tostring(sub_element)
    s += element.tail
    return s

答案 2 :(得分:3)

这些是很好的答案,可以回答OP的问题,特别是如果问题仅限于HTML。但是文档本质上是混乱的,元素嵌套的深度通常是无法预测的。

要模拟DOM的getTextContent(),您必须使用(非常)简单的递归机制。

只获取裸文:

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 doc(.fodt文件)中单个para的示例输出:

(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字符。

当然,主要是以英语为中心的#34;这个讨论得到了更大的微妙和复杂性!

答案 3 :(得分:2)

我怀疑ElementTree是用来做这件事的。但假设您有充分的理由使用它,也许您可​​以尝试从片段中剥离根标记:

 re.sub(r'(^<%s\b.*?>|</%s\b.*?>$)' % (element.tag, element.tag), '', ElementTree.tostring(element))

答案 4 :(得分:1)

此处的大多数答案都基于XML解析器ElementTree,甚至PEZ's regex-based answer仍然部分依赖于ElementTree。

所有这些都很好并适合大多数用例,但是,为了完整起见,值得注意的是,ElementTree.tostring(...)会给你一个等效的片段,但并不总是与原始有效载荷相同。如果由于某种非常罕见的原因,您希望按原样提取内容,则必须使用纯正的基于正则表达式的解决方案。 This example是我使用基于正则表达式的解决方案。

答案 5 :(得分:0)

此答案是对 Pupeno的 答复的略微修改。在这里,我将编码类型添加到“ 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

答案 6 :(得分:-4)

不知道外部库是否可能是一个选项,但无论如何 - 假设页面上有一个<p>带有此文本,jQuery解决方案将是:

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