【问题标题】:Python: Parsing through XML with mini domPython:使用 mini dom 解析 XML
【发布时间】:2013-03-29 18:45:50
【问题描述】:

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

这是我的代码的 sn-p:(程序的其余部分,我已经测试过,它们工作正常) 编辑:更改为包含测试 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 块(见上文)后,我发现: 在架构中,有一些称为“药物相互作用”的部分有一个称为药物的子字段。像这样:

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

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

【问题讨论】:

  • 能否包含错误的堆栈跟踪?
  • 是的,编辑了我遇到的最近的 2 个错误,除了添加/删除打印语句之外没有改变太多其他内容。
  • 您的代码假定记录始终具有您认为的格式。 KeyError 仅表示 drug 元素没有 type 属性。 IndexError 的类似问题...记录没有您想要的信息。尝试将“for entry in druglist:”块放入 try/except 块,然后打印导致问题的条目。看起来对吗?从长远来看,除了处理程序会实施您的失败策略(继续处理、报告记录或其他)。
  • @tdelaney 起初我认为这可能是导致错误的原因,但是当我检查数据时,每个药物字段都带有类型属性,并且每个药物都必须带有药物 ID 和药物名称。即使使用数据源,我也检查了这一点。他们每个人都必须在那里。这就是我难过的原因。我将放入一个 try/except 块并进行更多检查。
  • @Joe 如果drugs 是一个根元素,它只有drug 作为后续元素,在drugs 上使用childNodes 而不是getElementsByTagName。

标签: python xml parsing text-parsing


【解决方案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 循环遍历它们。

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

【讨论】:

    【解决方案2】:

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

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

    代码可能有点脆弱,因为我假设每个 &lt;drug&gt;&lt;/drug&gt; 对都在自己的行上。希望它的帮助大于它的危害。

    #!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/

    【讨论】:

    • 酷,我来看看。我最终自己也想通了,但我也会尝试一下。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2013-01-31
    相关资源
    最近更新 更多