2012-06-20 3 views
2

Я просмотрел несколько сообщений, но я не нашел ответов, которые решили мою проблему.Извлечение текста из узла XML с помощью 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 закрывают теги? Если я использую a.childNodes, я получаю [].

Когда я получаю тип узла для a, это тип 1 и TEXT_NODE = 3. Я не уверен, что это полезно.

Я хотел бы извлечь TEXT1, TEXT2 и т.д.

+0

Ваши 'TEXT1',' TEXT2' и т. Д. На самом деле не являются участниками какого-либо элемента. Если ваш XML будет ' TEXT1 TEXT2 TEXT3'? Кроме того, существует закрывающий тег ''? – Chris

+1

Кроме того, я настоятельно рекомендую использовать ['xml.etree.ElemetTree'] (http://docs.python.org/library/xml.etree.elementtree.html) (часть стандартной библиотеки) для работы с XML в Python. Это гораздо более простой и более пифонический интерфейс. Например, в '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 s.

Если вы хотите разобрать какой-либо XML, такой как <Node id="0">TEXT1</Node>, вам придется заменить строку [element.tail for element in xml_etree] на [element.text for element in xml_etree].

1

Вы должны использовать apiElementTree 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'. –

 Смежные вопросы

  • Нет связанных вопросов^_^