【问题标题】:Extracting text from XML node with minidom使用 minidom 从 XML 节点中提取文本
【发布时间】:2012-06-20 15:19:20
【问题描述】:

我浏览了几篇帖子,但还没有找到任何解决我问题的答案。

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

【问题讨论】:

  • 您的TEXT1TEXT2 等实际上不是任何元素的一方。你的 XML 应该是&lt;Node id="0"&gt;TEXT1&lt;/Node&gt;&lt;Node id="19"&gt;TEXT2&lt;/Node&gt;&lt;Node id="20"&gt;TEXT3&lt;/Node&gt;&lt;Node id="212" /&gt; 吗?另外,是否有关闭 &lt;TextWithNodes&gt; 标签?
  • 另外,我强烈建议使用xml.etree.ElemetTree(标准库的一部分)在 Python 中处理 XML。它是一个更简单、更 Pythonic 的界面。例如,在xml.dom 中,您必须使用element.childNodes.nodeValue 来获取与element 关联的文本,在etree 中这就是element.text
  • 嗨,克里斯,谢谢,我就是这么想的,因为它都是结束标签,这让我很困惑。我不确定这个 xml 文件的有效性,它只是一个文本工程软件的输出,用于注释,我需要将其解析为 excel。我将研究 ElementTree。

标签: python xml parsing minidom


【解决方案1】:

来自文档的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 中的文本不属于任何节点。

【讨论】:

  • 更准确地说,XML 中的文本属于TextWithNodes 元素,但不属于Node 元素。文本节点和Node 元素是兄弟元素,而不是子父元素。
  • 感谢@FrancisAvila 我仍在努力整理我的 xml 结构,这真的很有帮助!
  • @Jasmine,可能就是这样。我在最后添加了&lt;/TextWithNodes&gt;。如果您尝试我的代码,它将起作用。
  • 当我尝试提取特定节点的文本时,我得到“无”?
  • 是的,因为您在 XML 中拥有的节点是空的:&lt;Node id="0"/&gt;&lt;Node id="0"&gt;&lt;/Node&gt; 相同。你应该写类似&lt;Node id="0"&gt;TEXT1&lt;/Node&gt;
【解决方案2】:

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

您要查找的内容已作为textContent attribute 添加到 DOM 级别 3。 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 元素是这些文本节点的兄弟姐妹,而不是它们的父节点。

【讨论】:

  • 文本提取到哪里?
  • 我不明白您所说的“提取到”是什么意思。文本由textContent 函数返回。
【解决方案3】:

使用xml.etree.ElemetTree(类似于@DiegoNavrro 在他的回答中使用的 lxml,除了标准库中的 etree 并且没有 XPATH 等),您可以尝试以下操作:

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 &lt;Node id="0"/&gt;TEXT1... 是正确的。因为文本跟在结束标签之后,所以它成为标签的尾部文本。这不是元素 nodeValue,这就是为什么在你的代码中你得到Nones 的问题。

如果您想解析像&lt;Node id="0"&gt;TEXT1&lt;/Node&gt; 这样的XML,您必须将[element.tail for element in xml_etree] 行替换为[element.text for element in xml_etree]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    相关资源
    最近更新 更多