Я ищу способ получить определенные теги.. из очень большого xml документа с Python dom созданный в модуле
например:
<AssetType longname="characters" shortname="chr" shortnames="chrs">
<type>
pub
</type>
<type>
geo
</type>
<type>
rig
</type>
</AssetType>
<AssetType longname="camera" shortname="cam" shortnames="cams">
<type>
cam1
</type>
<type>
cam2
</type>
<type>
cam4
</type>
</AssetType>
я хочу получить значение детей узла AssetType, которые заставили атрибут (longname = "символы") иметь результат 'pub','geo','rig'
напомненный, что у меня есть больше чем 1 000 узлов <AssetType>
заранее спасибо
Если вы не возражаете загрузить весь документ в память:
from lxml import etree
data = etree.parse(fname)
result = [node.text.strip()
for node in data.xpath("//AssetType[@longname='characters']/type")]
Вам может потребоваться удалить пробелы в начале вашего теги, чтобы эта работа работала.
Предположим, что ваш документ называется assets.xml
и имеет следующую структуру:
<assets>
<AssetType>
...
</AssetType>
<AssetType>
...
</AssetType>
</assets>
Тогда вы можете сделать следующее:
from xml.etree.ElementTree import ElementTree
tree = ElementTree()
root = tree.parse("assets.xml")
for assetType in root.findall("//AssetType[@longname='characters']"):
for type in assetType.getchildren():
print type.text
Используйте xml.модуль sax . Создайте свой собственный обработчик и внутри startElement вы должны проверить, является ли имя AssetType. Таким образом, вы сможете действовать только тогда, когда обрабатывается узел AssetType.
Здесь у вас есть пример обработчика, который показывает, как его создать (хотя это не самый красивый способ, на тот момент я не знал всех крутых трюков с Python ;-)).
Аналогично решению eswald'а, снова удаление пробельных символов, снова загрузка документа в память, но возврат трех элементов текста за раз
from lxml import etree
data = """<AssetType longname="characters" shortname="chr" shortnames="chrs"
<type>
pub
</type>
<type>
geo
</type>
<type>
rig
</type>
</AssetType>
"""
doc = etree.XML(data)
for asset in doc.xpath('//AssetType[@longname="characters"]'):
threetypes = [ x.strip() for x in asset.xpath('./type/text()') ]
print threetypes
Вы можете использовать xpath, что-то вроде "//AssetType[longname='characters']/xyz".
О либах XPath в Python смотрите http://www.somebits.com/weblog/tech/python/xpath.html
Вы можете использовать pulldom API для обработки большого файла, не загружая его сразу в память. Это обеспечивает более удобный интерфейс, чем использование SAX, с небольшой потерей производительности.
По сути, это позволяет вам передавать XML-файл в потоковом режиме, пока вы не найдете интересующий вас бит, а затем начать использовать обычные операции DOM после этого.
from xml.dom import pulldom
# http://mail.python.org/pipermail/xml-sig/2005-March/011022.html
def getInnerText(oNode):
rc = ""
nodelist = oNode.childNodes
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
elif node.nodeType==node.ELEMENT_NODE:
rc = rc + getInnerText(node) # recursive !!!
elif node.nodeType==node.CDATA_SECTION_NODE:
rc = rc + node.data
else:
# node.nodeType: PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE, NOTATION_NODE and so on
pass
return rc
# xml_file is either a filename or a file
stream = pulldom.parse(xml_file)
for event, node in stream:
if event == "START_ELEMENT" and node.nodeName == "AssetType":
if node.getAttribute("longname") == "characters":
stream.expandNode(node) # node now contains a mini-dom tree
type_nodes = node.getElementsByTagName('type')
for type_node in type_nodes:
# type_text will have the value of what's inside the type text
type_text = getInnerText(type_node)