使用minidom从XML节点提取文本

时间:2012-06-20 15:19:21

标签: python xml parsing minidom

我查看了几个帖子,但我还没有找到解决问题的任何答案。

示例XML =

<TextWithNodes>
<Node id="0"/>TEXT1<Node id="19"/>TEXT2 <Node id="20"/>TEXT3<Node id="212"/>
</TextWithNodes>

所以我理解,通常如果我将TextWithNodes提取为NodeList我会做类似的事情

nodeList = TextWithNodes[0].getElementsByTagName('Node')
for a in nodeList:
    node = a.nodeValue
    print node

我得到的只是None。我已经读过你必须写a.childNodes.nodeValue但是节点列表中没有子节点,因为看起来所有Node ID都在关闭标签?如果我使用a.childNodes,我会获得[]

当我获得a的节点类型时,它是类型1而TEXT_NODE = 3.我不确定这是否有用。

我想提取TEXT1TEXT2

3 个答案:

答案 0 :(得分:2)

来自文档的lxml解决方案:

from lxml import etree
from StringIO import StringIO

xml = etree.parse(StringIO('''<TextWithNodes>
<Node id="0"/>TEXT1<Node id="19"/>TEXT2 <Node id="20"/>TEXT3<Node id="212"/></TextWithNodes>'''))

xml.xpath("//text()")
Out[43]: ['\n', 'TEXT1', 'TEXT2 ', 'TEXT3']

您还可以提取特定节点的文本:

xml.find(".//Node[@id='19']").text

这里的问题是XML中的文本不属于任何节点。

答案 1 :(得分:1)

您应该使用ElementTree api而不是minidom来完成您的任务(如此处的其他答案中所述),但如果您需要使用minidom,这里有一个解决方案。

您正在寻找的内容被添加到DOM级别3作为textContent attribute。 Minidom仅支持1级。

但是,您可以使用此函数非常接近地模拟textContent:

def textContent(node):
    if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
        return node.nodeValue
    else:
        return ''.join(textContent(n) for n in node.childNodes)

然后您可以这样使用:

x = minidom.parseString("""<TextWithNodes>
<Node id="0"/>TEXT1<Node id="19"/>TEXT2 <Node id="20"/>TEXT3<Node id="212"/></TextWithNodes>""")

twn = x.getElementsByTagName('TextWithNodes')[0]

assert textContent(twn) == u'\nTEXT1TEXT2 TEXT3'

请注意我是如何获得父节点TextWithNodes的文本内容的。这是因为您的Node元素是这些文本节点的兄弟,而不是它们的父节点。

答案 2 :(得分:0)

使用xml.etree.ElemetTree(类似于@DiegoNavrro在其答案中使用的lxml,除了部分标准库中的etree以及没有XPATH等),您可以给出以下内容:< / p>

import xml.etree.ElementTree as etree

xml_string = """<TextWithNodes>
<Node id="0"/>TEXT1<Node id="19"/>TEXT2 <Node id="20"/>TEXT3<Node id="212"/>
</TextWithNodes>
"""

xml_etree = etree.fromstring(xml_string)

text = [element.tail for element in xml_etree]
# `text` will be ['TEXT1', 'TEXT2 ', 'TEXT3', '\n']

注意,这假设XML <Node id="0"/>TEXT1 ...是正确的。因为文本在结束标记之后,所以它成为标记的尾部文本。它不是元素nodeValue,这就是为什么在问题的代码中你得到None s。

如果您想解析某些XML,例如<Node id="0">TEXT1</Node>,则必须将行[element.tail for element in xml_etree]替换为[element.text for element in xml_etree]