Python:使用mini dom解析XML

时间:2013-03-29 18:45:51

标签: python xml parsing text-parsing

我正在解析一个体面的xml文件,我遇到了一个问题。出于某种原因,我无法提取数据,即使我之前在不同的xml文件上完成了完全相同的事情

这是我的代码片段:(程序的其余部分,我已经过测试,它们工作正常) 编辑:更改为包括测试尝试&除块

def parseXML():
    file = open(str(options.drugxml),'r')
    data = file.read()
    file.close()
    dom = parseString(data)
    druglist = dom.getElementsByTagName('drug')

    with codecs.open(str(options.csvdata),'w','utf-8') as csvout, open('DrugTargetRel.csv','w') as dtout:
        for entry in druglist:
        count = count + 1
        try:
            drugtype = entry.attributes['type'].value
            print count
        except:
            print count
            print entry
            drugidObj = entry.getElementsByTagName('drugbank-id')[0]
            drugid = drugidObj.childNodes[0].nodeValue
            drugnameObj = entry.getElementsByTagName('name')[0]
            drugname = drugnameObj.childNodes[0].nodeValue

            targetlist = entry.getElementsByTagName('target')
            for target in targetlist:
                targetid = target.attributes['partner'].value
                dtout.write((','.join((drugid,targetid)))+'\n')

            csvout.write((','.join((drugid,drugname,drugtype)))+'\n')

如果你想知道XML文件的架构大致是什么样子,这里是一个粗略的神奇的层次草图:

<drugs>
   <drug type='something' ...>
      <drugbank-id>
      <name>
      ...
      <targets>
         <target partner='something'>

我在这里输入的内容,我需要从XML文件中提取并将其粘贴在csv文件中(如上面的代码所示),并且代码之前已经适用于不同的xml文件,不知道为什么它不能正常工作这个。我已经在'type'上得到了KeyError,即使每种药物都含有一种药物,我也会在线上提取索引错误。我搞砸了什么?

编辑:我正在提取的东西保证在每种药物中。

对于任何关心的人,这里是我正在解析的XML文件的链接: http://www.drugbank.ca/system/downloads/current/drugbank.xml.zip

编辑:实施尝试后&amp;除了块(见上文)这里是我发现的: 在模式中,有一些称为“药物相互作用”的部分有一个名为 drug 的子字段。像这样:

 <drugs>
       <drug type='something' ...>
          <drugbank-id>
          <name>
          ...
          <targets>
             <target partner='something'>
          <drug-interactions>
             <drug>

我认为我的药物药物清单= dom.getElementsByTagName('drug')也是无意中挑选的 - 我不知道如何解决这个问题......有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我有一种感觉,可能是由于内存不足或其他东西而发生了一些奇怪的事情,所以我使用迭代器重写了每个药物的解析器并尝试了它并让程序完成而不会引发异常。 / p>

基本上我在这里做的是,不是将整个XML文件加载到内存中,而是解析每个<drug></drug>标记的开头和结尾的XML文件。然后我每次用小型号解析它。

代码可能有点脆弱,因为我假设每个<drug></drug>对都在他们自己的行上。希望它有助于避免伤害。

#!python
import codecs
from xml.dom import minidom

class DrugBank(object):
    def __init__(self, filename):
        self.fp = open(filename, 'r')

    def __iter__(self):
        return self

    def next(self):
        state = 0

        while True:
            line = self.fp.readline()

            if state == 0:
                if line.strip().startswith('<drug '):
                    lines = [line]
                    state = 1
                    continue

                if line.strip() == '</drugs>':
                    self.fp.close()
                    raise StopIteration()

            if state == 1:
                lines.append(line)
                if line.strip() == '</drug>':
                    return minidom.parseString("".join(lines))

with codecs.open('csvout.csv', 'w', 'utf-8') as csvout, open('dtout.csv', 'w') as dtout:
    db = DrugBank('drugbank.xml')
    for dom in db:
        entry = dom.firstChild
        drugtype = entry.attributes['type'].value
        drugidObj = entry.getElementsByTagName('drugbank-id')[0]
        drugid = drugidObj.childNodes[0].nodeValue
        drugnameObj = entry.getElementsByTagName('name')[0]
        drugname = drugnameObj.childNodes[0].nodeValue

        targetlist = entry.getElementsByTagName('target')
        for target in targetlist:
            targetid = target.attributes['partner'].value
            dtout.write((','.join((drugid,targetid)))+'\n')

        csvout.write((','.join((drugid,drugname,drugtype)))+'\n')

有趣的读物可能会对您有所帮助: http://www.ibm.com/developerworks/xml/library/x-hiperfparse/

答案 1 :(得分:1)

基本上在分析xml时,你不能依赖于你知道结构的事实。在代码中找出结构是一种很好的做法。

因此,每次访问元素或属性时,请先检查是否存在。在您的代码中,它意味着:

确保有一个属性&#39; type&#39;关于药物成分:

drugtype = entry.attributes['type'].value if entry.attributes.has_key('type') else 'defaulttype'

确保getElementsByTagName在访问其元素之前不返回空数组:

drugbank-id = entry.getElementsByTagName('drugbank-id')
drugidObj = drugbank-id[0] if drugbank-id else None

在访问子节点之前,请确保有以下内容:

if drugidObj.hasChildNodes:
    drugid = drugidObj.childNodes[0].nodeValue

或者使用循环来循环遍历它们。

当你在药物elemet上调用getElementsByTagName时,它会返回所有元素,包括嵌套的元素。要获得药物元素,这些药物元素是药物元素的直接子元素,您必须使用childNodes属性。