Как получить конкретные узлы в XML-файле с Python - PullRequest
5 голосов
/ 09 февраля 2010

я ищу способ получить определенные теги .. из очень большого 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 = "characters") иметь результат 'pub','geo','rig'
пожалуйста, помните, что у меня более 1000 узлов
спасибо заранее

Ответы [ 6 ]

5 голосов
/ 09 февраля 2010

Предполагается, что ваш документ называется 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
3 голосов
/ 09 февраля 2010

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

2 голосов
/ 09 февраля 2010

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

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

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

2 голосов
/ 09 февраля 2010

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

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

1 голос
/ 09 февраля 2010

Аналогично решению 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 голос
/ 09 февраля 2010

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

Для библиотек XPath в Python см. http://www.somebits.com/weblog/tech/python/xpath.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...