0

我正在解析一个大小合适的 xml 文件,但遇到了问题。出于某种原因,即使我之前对不同的 xml 文件做了完全相同的事情,我也无法提取数据。

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

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,即使每种药物都有一个drugid,我也得到了提取drugid的索引错误。我在这里搞砸什么?

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

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

编辑:在实现 try & except 块(见上文)后,我发现:在架构中,有一些称为“药物相互作用”的部分有一个名为drug的子字段。所以像这样:

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

我认为我的行 druglist = dom.getElementsByTagName('drug') 也无意中捡起了这些——我不知道如何解决这个问题……有什么建议吗?

4

2 回答 2

1

我有一种感觉,可能由于内存不足或其他原因发生了一些奇怪的事情,所以我使用迭代器对每种药物重写了解析器,并尝试了它并让程序在没有引发异常的情况下完成。

基本上我在这里所做的是,我没有将整个 XML 文件加载到内存中,而是解析 XML 文件以查找每个<drug>and</drug>标记的开头和结尾。然后我每次都用 minidom 解析它。

代码可能有点脆弱,因为我假设每个<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/

于 2013-03-29T19:44:39.980 回答
1

基本上,在解析 xml 时,您不能依赖于您知道结构的事实。找出代码中的结构是一个好习惯。

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

确保药物元素上有一个属性“类型”:

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

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

当您调用getElementsByTagNamedrug elemet 时,它会返回所有元素,包括嵌套元素。要仅获取药物元素,它们是药物元素的直接子元素,您必须使用childNodes属性。

于 2013-03-29T20:19:56.043 回答