2010-02-09 15 views
4

IM ищет способ, чтобы получить конкретные тег .. с очень большим документом XML с питона йотом встроенного модулем
, например:
как получить конкретные узлы в XML-файл с питоном

<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'
пожалуйста, положить в виду, что у меня есть более чем 1000 < AssetType> узлы
thanx заблаговременно

ответ

2

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

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

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

+1

Это мой подход. Имейте в виду, что для этого требуется установка модуля lxml, который не является частью библиотек Python по умолчанию. Тем не менее, я использую его в проекте прямо сейчас, когда некоторые из файлов XML имеют размер в 65 мегабайт, и он не жалуется (в отличие от автора сценария). – Tom

+0

+1 для 'lxml.etree', который значительно превосходит стандартную установку' ElementTree'. – jathanism

2

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

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

3

Вы можете использовать pulldom API, чтобы обрабатывать синтаксический анализ большого файла, не загружая его сразу в память. Это обеспечивает более удобный интерфейс, чем использование SAX с небольшой потерей производительности.

Он в основном позволяет вам передавать XML-файл, пока не найдете интересующий вас бит, а затем начните использовать regular DOM operations.


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) 

1

Аналогично решению 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 
4

Предположим, что ваш документ называется 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 
+0

+1 для решения по умолчанию. Портативность камней! – jathanism

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