2012-06-20 86 views
2

我已經瀏覽了幾篇文章,但我還沒有找到任何解決我的問題的答案。用minidom從XML節點中提取文本

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

+0

你的'TEXT1','TEXT2'等實際上並不是任何元素的派對。如果你的XML是' TEXT1 TEXT2 TEXT3'?另外,是否有關閉的標籤? – Chris

+1

此外,我強烈建議使用['xml.etree.ElemetTree'](http://docs.python.org/library/xml.etree.elementtree.html)(標準庫的一部分)來處理XML蟒蛇。這是一個更簡單,更pythonic的界面。例如,在'xml.dom'中,你必須使用'element.childNodes.nodeValue'來獲取與'element'相關的文本,在etree中這只是'element.text'。 – Chris

+0

嗨克里斯,謝謝,那正是我所想的,因爲它全部關閉標籤,這讓我很困惑。我不確定這個xml文件有多有效,它只是一個文本工程軟件的輸出,用於註解,我需要解析爲excel。我會考慮ElementTree。 – Jasmine

回答

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

更確切地說,XML中的文本屬於'TextWithNodes'元素,但不屬於'Node'元素。文本節點和Node節點是兄弟節點,而不是父節點。 –

+0

是的,@FrancisAvila,你是對的 –

+0

謝謝@FrancisAvila我仍然試圖組織我的XML結構頭,這真的很有幫助! – Jasmine

0

使用xml.etree.ElemetTree(類似於限於lxml這@DiegoNavrro在他的回答中,除了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 <Node id="0"/>TEXT1 ...是正確的。由於文本緊跟在結束標籤之後,因此它成爲標籤的尾部文本。它不是元素nodeValue,這就是爲什麼在你的代碼中你得到的問題是None

如果您想分析一些XML,如<Node id="0">TEXT1</Node>,您將不得不用[element.text for element in xml_etree]替換行[element.tail for element in xml_etree]

1

您應該使用ElementTree api代替您的任務(如其他答案中所述),但是如果您需要使用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元素是兄弟那些文本節點,而不是它們的父母。

+0

將文本提取到哪裏? – Jasmine

+0

我不明白你的意思是「提取到」。該文本由'textContent'函數返回。 –