#!/usr/bin/python
"""
Classes to read and process MedLine XML record files, for use in processing modules.

They can handle the XML format used by PubMed and MedLine services, for example as returned by eutils online services

   >>> xml_records = urllib.urlopen('http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id='+list_of_pmids+'&retmode=xml').read()

When used, an object is created as a global repository, from which records (also objects) can be queried and extracted. These record-objects have properties like title, authors, abstracts that return their string values.

Somewhat long loading times can be shortened later by serializing objects using  cPickle module

   USAGE:
   >>> from BioReader import *
   >>> data = DataContainer('AllAbstracts.xml','pubmed')
   >>> data.howmany # len(data.dictRecords.keys())
   >>> data.keys    # data.dictRecords.keys()
   >>> record = data.Read('7024555')
   >>> record.title

           u'The birA gene of Escherichia coli encodes a biotin holoenzyme synthetase.'
           record +
                  - B{.title}
                  - B{.pmid}
                  - B{.Abs} I{(abstracts)}
                  - B{.year}
                  - B{.journal}
                  - B{.auth} I{(list of authors)}
                  - B{.m} I{(list of MeSH keywords, descriptors and qualifiers)}
                  - B{.MD} I{(MesH Descriptors)}
                  - B{.MQ} I{(MesH Qualifiers, if any)}
                  - B{.MDMay} I{(list of Mayor MesH Descriptors, if any)}
                  - B{.MQMay} I{(list of Mayor MesH Qualifiers, if any)}
                  - B{.paper} I{(full text flat file if exists in user-defined repository

The Search method inside the DataContainer class is not working well, and should be rewritten  using better XML techniques and methods

A class (CreateXML) has been added recently to create the pubmed XML file from a list of PubMed ids. Has not been fully integrated with the data container class

Another class shoud be able to query keywords directly to pubmed, to either get the pubmed ids or the xml directly, using either BioPython's PubMed modules of directly through Eutil's facilities

""" 
#__docformat__ = 'epytext en'

# General info
__version__ = '5.0'
__author__ = 'Carlos Rodriguez'
__url__ = 'http://www.cnio.es'
__license__ = 'GNU'

from xml.dom.minidom import parseString
import string
import re
import os

class BioReader:
    """
    Class BioReader for BioMedical files
    """
    def __init__(self, string, path=None):
        """
        Initialize class with XML string  and returns record data and body of text objects.
        
            >>> single_record = BioReader(record)

            >>> single_record.title
            u'The birA gene of Escherichia coli encodes a biotin holoenzyme synthetase.'
         
            >>> single_record.pmid
            u'7024555'
            
        single_record +
           - B{.title}
           - B{.pmid}
           - B{.Abs} I{(abstracts)}
           - B{.year}
           - B{.journal}
           - B{.auth} I{(list of authors)}
           - B{.m} I{(list of MeSH keywords, descriptors and qualifiers)}
           - B{.MD} I{(MesH Descriptors)}
           - B{.MQ} I{(MesH Qualifiers, if any)}
           - B{.MDMay} I{(list of Mayor MesH Descriptors, if any)}
           - B{.MQMay} I{(list of Mayor MesH Qualifiers, if any)}
           - B{.paper} I{(full text flat file if exists in user-defined repository [see notes below])}
                  
        If we use a repository with full text papers (with pmid+<pmidnumber>+txt format), 
        we can use the following, after specifying it in the Data Container we instantiated:
        
             >>> data.Repository("/repositorio/Regulontxt/")

             >>> record = data.dictRecords['9209026']

             >>> single_record = BioReader(record,data.repository)# or directly inputing path, if it was  not done\\
                  through the DataContainer class: single_record = BioReader(record,'/path/to/repository/')

             >>> single_record.paper

             'Aerobic Regulation of the sucABCD Genes of Escherichia coli,Which Encode \xef\xbf\xbd-Ketoglutarate Dehydrogenase andSuccinyl Coenzyme A Synthetase: Roles of ArcA,Fnr, and the Upstream sdhCDAB Promoter\n.....'
             
        """
        self.tags = re.compile("<.*?>")
        self.parsed = parseString(string)
        self.document = self.parsed.documentElement
        self.pmid = self.document.getElementsByTagName("PMID")[0].firstChild.data
        self.year = self.document.getElementsByTagName("DateCreated")[0].getElementsByTagName("Year")[0].firstChild.data
        self.journal = self.document.getElementsByTagName("MedlineJournalInfo")[0].getElementsByTagName("MedlineTA")[0].firstChild.data
        self.testAbs = self.document.getElementsByTagName("Abstract")
        if path != None:
            self.path = path
            self.paper = self.GetFullPaper()
        else:
            self.path = None
            self.paper = None
        try:
            self.year = self.document.getElementsByTagName("PubDate")[0].getElementsByTagName("Year")[0].firstChild.data
        except IndexError:
            self.year = self.document.getElementsByTagName("DateCreated")[0].getElementsByTagName("Year")[0].firstChild.data
        try:
            self.Abs = self.document.getElementsByTagName("Abstract")[0].getElementsByTagName("AbstractText")[0].firstChild.data
        except IndexError:
            self.Abs = "n/a"
        self.title = self.document.getElementsByTagName("ArticleTitle")[0].firstChild.data
        try:
            self.authorsList = self.document.getElementsByTagName("AuthorList")[0].getElementsByTagName("Author")
            self.Lista = [self.authorize(y.childNodes) for y in self.authorsList]
            s = ""
            for x in self.Lista:
                s = s + x + "\n"
            self.auth = s
        except AttributeError:
            self.auth = " "
        except IndexError:
            self.auth = " "
        try:
            self.meshes = self.document.getElementsByTagName("MeshHeadingList")[0].getElementsByTagName("MeshHeading")
            self.ListaMs = [self.Meshes(z.childNodes) for z in self.meshes]
            self.MD = []
            self.MQ = []
            self.MDMay = []
            self.MQMay = []
            for z in self.meshes:
                MD,MQ,MDMay,MQMay = self.MeshKeys(z)
                self.MD = MD + self.MD