如何将保留特定标签或其内容的XML解析为纯文本?

时间:2019-06-22 15:20:38

标签: python xml

我正在解析XML格式的文档,该文档支持一些类似HTML的标记,包括内联格式标记。我想以正常方式解析所有标签,但不解析p标签的内容,因此我可以以结构感知的方式使用结构化数据,并退回纯文本操作以获取文本内容和格式。例如

<root>
    <data1><field1>qwerty</field1> <field2>qwerty</field2> </data1>
    <body>
        <p>Lorem ipsum</p>
        <p>Dolor <a href="http://example.com">sit</a> <em><strong>amet</strong> consectetuer</em></p>
    </body>
</root>

应该导致一棵树,其中根元素包含一个data1元素和一个body元素; data1元素包含field1和field2元素(应删除这些标签之后的空格); body元素包含2个p元素,但p个元素(全部)不包含任何子标记,并将其全部内容公开为文本字符串。

即给定第二个p标签对象,我希望满足以下条件:

p.text == 'Dolor <a href="http://example.com">sit</a> <em><strong>amet</strong> consectetuer'

这是否要通过“将ap标签中包含的所有内容作为纯文本处理”或“将a,em和strong标签作为任何地方的纯文本处理”都没有关系尽管我对同时了解这两种方式都很感兴趣。

实际上,提到的标签并不是唯一相关的标签,我需要能够指定该原理将适用的标签的名称。

如何在Python中以这种方式解析XML?

使用哪个XML库对我来说都没有关系。我以前从未在Python中使用过XML,到目前为止还没有选择XML。我现在正在使用lxml(因为我已经读过它可以自动解码ASCII文件并具有更好的XPath支持,它也不会像ElementTree那样与名称空间快捷方式混为一谈),但是它们太多了(ElementTree,MiniDOM,lxml ,Untangle,BeautifulSoup等),我真的不知道哪个更适合我。顺便说一句,无论谁知道Python XML库的比较好概述,如果您能在评论中共享指向它的链接,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

这里

import xml.etree.ElementTree as ET

xml = '''<root>
    <data1><field1>qwerty</field1> <field2>qwerty</field2> </data1>
    <body>
        <p>Lorem ipsum</p>
        <p>Dolor <a href="http://example.com">sit</a> <em><strong>amet</strong> consectetuer</em></p>
    </body>
</root>'''

TEST_STRINGS = ['<p>Lorem ipsum</p>',
                '<p>Dolor <a href="http://example.com">sit</a> <em><strong>amet</strong> consectetuer</em></p>']


def _add_text_before_traversing_tree(e):
    return e.tag in ['p']


def _handle_attrib(attrib):
    result = ''
    for k, v in attrib.items():
        result += '{}="{}"'.format(k, v)
    return ' ' + result if result else ''


def _element_to_text(e, tree_fragments):
    tree_fragments.append('<{}'.format(e.tag))
    if not e.attrib:
        tree_fragments.append('>')
    tree_fragments.append(_handle_attrib(e.attrib))
    add_text_now = _add_text_before_traversing_tree(e)
    if add_text_now:
        tree_fragments.append(e.text if e.text else '')
    for child in list(e):
        _element_to_text(child, tree_fragments)
    if not add_text_now:
        if not e.attrib:
            tree_fragments.append(e.text if e.text else '')
        else:
            tree_fragments.append('>' + e.text if e.text else '')
    tree_fragments.append('</{}>'.format(e.tag))
    tree_fragments.append(e.tail.strip() if e.tail else '')


def element_to_text(e):
    """ Traverse element tree and return a string representation of the tree"""
    tree_fragments = []
    _element_to_text(e, tree_fragments)
    tree_fragments = [x for x in tree_fragments if len(x) > 0]
    return ''.join(tree_fragments)


root = ET.fromstring(xml)
p_elements = root.findall('./body/p')
for idx, p in enumerate(p_elements):
    element_as_text = element_to_text(p)
    print('Original text  : ' + TEST_STRINGS[idx])
    print('Element as text: ' + element_as_text)
    print('')
    # now you need to create a new element,
    # attach it to the parent element ('body'),
    # set its new text and remove the current element

输出

Original text  : <p>Lorem ipsum</p>
Element as text: <p>Lorem ipsum</p>

Original text  : <p>Dolor <a href="http://example.com">sit</a> <em><strong>amet</strong> consectetuer</em></p>
Element as text: <p>Dolor <a href="http://example.com">sit</a><em><strong>amet</strong>consectetuer</em></p>