как получить определенные узлы в XML-файле с Python

Я ищу способ получить определенные теги.. из очень большого 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>
заранее спасибо

5
задан Fred Larson 9 February 2010 в 16:36
поделиться

6 ответов

Если вы не возражаете загрузить весь документ в память:

from lxml import etree
data = etree.parse(fname)
result = [node.text.strip() 
    for node in data.xpath("//AssetType[@longname='characters']/type")]

Вам может потребоваться удалить пробелы в начале вашего теги, чтобы эта работа работала.

2
ответ дан 18 December 2019 в 13:14
поделиться

Предположим, что ваш документ называется 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
5
ответ дан 18 December 2019 в 13:14
поделиться

Используйте xml.модуль sax . Создайте свой собственный обработчик и внутри startElement вы должны проверить, является ли имя AssetType. Таким образом, вы сможете действовать только тогда, когда обрабатывается узел AssetType.

Здесь у вас есть пример обработчика, который показывает, как его создать (хотя это не самый красивый способ, на тот момент я не знал всех крутых трюков с Python ;-)).

2
ответ дан 18 December 2019 в 13:14
поделиться

Аналогично решению 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
1
ответ дан 18 December 2019 в 13:14
поделиться

Вы можете использовать xpath, что-то вроде "//AssetType[longname='characters']/xyz".

О либах XPath в Python смотрите http://www.somebits.com/weblog/tech/python/xpath.html

1
ответ дан 18 December 2019 в 13:14
поделиться

Вы можете использовать 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)

3
ответ дан 18 December 2019 в 13:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: