Ignore:
Timestamp:
25/06/09 11:52:47 (10 years ago)
Author:
sdonegan
Message:

Now includes classes to handle ingest identityTransforms by xquery and elementtree. Ingest now uses elementtree to convert urls on given xpath to go via ndg redirection service

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI01-discovery/branches/ingestAutomation-upgrade/OAIBatch/Utilities.py

    r4854 r5413  
    11from xml.etree import ElementTree as ET 
    2 import logging 
     2import logging,pkg_resources 
    33from ndg.common.src.lib.ETxmlView import loadET, nsdumb 
     4from ndg.common.src.models.ndgObject import ndgObject 
     5from ndg.common.src.lib.ndgresources import ndgResources 
     6import ndg.common.src.lib.fileutilities as FileUtilities 
    47 
    58def idget(xml,dataType='DIF'): 
     
    1518    else: 
    1619        raise TypeError,'idget does not support datatype [%s]'%dataType 
     20  
     21import os, sys, logging 
     22 
     23''' 
     24        Class to handle identityTransform and correct UTF handling of parsable URLS for use in the ndg redirect service 
     25 
     26        Currently handles either DIF or MDIP input format 
     27 
     28        Steve Donegan June 2009 STFC RAL 
     29''' 
     30 
     31from xml.etree import ElementTree as ET 
     32import logging,urllib 
     33 
     34class redirectUrlChanger: 
     35 
     36         
     37 
     38        ''' Reads XML vocab structure. ''' 
     39        def __init__(self,filenameIP,outputFilenameIP,formatIP,redirectURLIP): 
     40                 
     41                self.format = formatIP 
     42                self.filename = filenameIP 
     43                self.outputFilename = outputFilenameIP 
     44                self.redirectBaseURL = redirectURLIP 
     45                                 
     46                #parse the xml with elementtree 
     47                self.etree=ET.parse(self.filename) 
     48                self.root=self.etree.getroot() # should be the "vocab" element 
     49 
     50                #look for and change relevant portions 
     51                self.changeUrl() 
     52                 
     53                #rewrite this back into the xml doc      
     54                self.etree.write(self.outputFilename) 
     55 
     56                 
     57        ''' 
     58        Method to obtain and change selected URLs 
     59        ''' 
     60        def changeUrl(self): 
     61                 
     62                #get document id 
     63                #note as appendNameSPace returns a list, must define which element, only one entry_id so 0 here... (java is so much better at this). 
     64                 
     65                 
     66                try: 
     67                        docTitle = self.root.find(self.appendNameSpace(self.datasetTitle())[0]).text 
     68                except: 
     69                        #doesnt matter too much if this doesnt work! 
     70                        docTitle = 'NOT_AVAILABLE' 
     71                 
     72                try: 
     73                         
     74                        docID = self.root.find(self.appendNameSpace(self.getIdPath())[0]).text 
     75                         
     76                        self.paths = self.appendNameSpace(self.URLpaths()) 
     77 
     78                        for path in self.paths: 
     79                         
     80                                nodes = self.root.findall(path) 
     81 
     82                                for node in nodes: 
     83                                        currentURL = urllib.quote(node.text) 
     84                                        redirectURL = self.redirectBaseURL + currentURL + '&docID=' + urllib.quote(docID) + '&docTitle=' + urllib.quote(docTitle)                
     85                                        node.text = redirectURL 
     86                 
     87                except: 
     88                        print "Cannot perform identityTransform to rewrite ndg redirect urls!" 
     89                        logging.warn("Cannot perform identityTransform to rewrite ndg redirect urls!") 
     90 
     91                 
     92                        #cannot rewrite doc so just leave doc as original.. 
     93         
     94         
     95        ''' 
     96        Method to convert the given xpath list to a namespace abbreviated version so elementtree can handle it (grrr.) 
     97        ''' 
     98        def appendNameSpace(self,paths): 
     99                 
     100                nameSpaceAppendedPaths = [] 
     101 
     102                for path in paths:                       
     103                        pathElements = path.split('/') 
     104                         
     105                        #note due to crappy elementtree have to avoid initial "/" 
     106                        count = 0 
     107                        for element in pathElements: 
     108                                if count == 0: 
     109                                        appendedPath = self.returnNS() + element 
     110                                else: 
     111                                        appendedPath = appendedPath + '/' + self.returnNS() + element 
     112                                 
     113                                count += 1 
     114                                                         
     115                        nameSpaceAppendedPaths.append(appendedPath) 
     116 
     117                return nameSpaceAppendedPaths 
     118 
     119         
     120        '''method to handle xpath to title for acceptable formats''' 
     121        def datasetTitle(self): 
     122                if self.format == 'DIF': 
     123                        return ['Entry_Title'] 
     124                elif self.format == 'MDIP': 
     125                        return ['Title'] 
     126 
     127        '''method to handle xpath for id if for reqd format ''' 
     128        def getIdPath(self): 
     129                if self.format == 'DIF': 
     130                        return ['Entry_ID'] 
     131                elif self.format == 'MDIP': 
     132                        return ['DatasetIdentifier'] 
     133 
     134        '''method to handle xpath for expected URLS if for reqd format ''' 
     135        def URLpaths(self): 
     136                if self.format == 'DIF': 
     137                        return ['Related_URL/URL','Data_Center/Data_Center_URL'] 
     138                elif self.format == 'MDIP': 
     139                        return ['OnlineResource','Distributor/Web'] 
     140 
     141        '''method to handle default namespaces for reqd format ''' 
     142        def returnNS(self): 
     143                if self.format == 'DIF': 
     144                        return '{http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/}' #Note that ns has to be encapsulated in {}'s! 
     145                elif self.format == 'MDIP': 
     146                        return '{http://www.oceannet.org/mdip/xml}' 
     147 
     148''' 
     149Class operating the identity transform of new ingest docs to change all urls to include a redirect via the ndg redirect service 
     150so can record all traffic from discovery service elsewhere.  Rewrites back to original filename so can continue with ingest 
     151''' 
     152class ndgRedirectTransform: 
     153 
     154    def __init__(self, xQueryType,ndgRedirect,dir): 
     155 
     156            
     157        SAXON_JAR_FILE = 'lib/saxon9.jar' 
     158 
     159        
     160        _repository_local_id = 'notneeded' 
     161        _local_id = 'notneeded' 
     162 
     163        xqueryLib = ndgResources()         
     164        xquery = xqueryLib.createXQuery(xQueryType,dir, _repository_local_id, _local_id) 
     165        xquery = xquery.replace('INPUT_FILE',dir) 
     166        xquery = xquery.replace('NDG_REDIRECT_URL',ndgRedirect) 
     167 
     168        #generate the actual xqueryFile 
     169        xqFile = "redirectQuery_"+xQueryType+".xq" 
     170        FileUtilities.createFile(xqFile, xquery) 
     171         
     172 
     173        # ensure the jar file is available - NB, this may be running from a different 
     174        # location - e.g. the OAIInfoEditor.lib.harvester - and this won't have the 
     175        # saxon file directly on its filesystem 
     176        jarFile = pkg_resources.resource_filename('OAIBatch','lib/saxon9.jar') 
     177 
     178        # Now do the transform 
     179        os.putenv ('PATH', ':/usr/java/jdk1.5.0_03/bin:/usr/java/jdk1.5.0_03:/usr/java/jdk1.5.0_03/lib/tools.jar:/usr/local/WSClients/OAIBatch:/usr/local/exist-client/bin:/bin:/usr/bin:.') 
     180        xqCommand = "java -cp %s net.sf.saxon.Query %s !omit-xml-declaration=yes" %(jarFile, xqFile) 
     181        logging.debug("Running saxon command: " + xqCommand) 
     182        pipe = os.popen(xqCommand + " 2>&1") 
     183        output = pipe.read() 
     184        status = pipe.close() 
     185                         
     186        if status is not None: 
     187            raise SystemError, 'Failed at running the XQuery' 
     188        else: 
     189            #write the output to a file for the rest of the ingest chain 
     190            FileUtilities.createFile(dir, output) 
     191         
     192            logging.info("Have performed identityTransform on " + dir) 
     193         
     194        
     195''' 
     196Class representing a record to be deleted from the postgres DB.  Mimics the class "PostgresRecord" as passed to PostgresDAO 
     197This is so we can use the PostgresDAO class for DB manipulation 
     198 
     199Merged into Utilities June 2009 SJD 
     200'''    
     201class RecordToDelete: 
     202     
     203    '''  
     204    Class representing a document to be deleted from the postgres DB  
     205    @param filename: Name of the original_document_file    
     206    ''' 
     207     
     208    def __init__(self, filename, discovery_ID): 
     209         
     210         
     211        #this relates to the "original_document_filename" column in the original_document table 
     212        if filename is not None: 
     213            self.filename = filename 
     214        else: 
     215            self.filename = "temporaryFilename" 
     216             
     217        if discovery_ID is not None: 
     218            self.discovery_id = discovery_ID 
     219        else: 
     220            self.discovery_id = "temporaryDiscoveryID" 
     221         
     222        # initialise the various record fields 
     223        self.db_id = None    # the DB ID of the record, for easy reference when it is created 
     224         
     225 
     226class DatasetBasicParameters: 
     227     
     228    '''  
     229    Class representing extracted parameters from the input file 
     230    @param filename: Name of the original_document_file    
     231    ''' 
     232     
     233    def __init__(self, filename,format): 
     234         
     235        logging.info("Retrieving identifier for metadata record " + filename + " in format: " + format) 
     236        xml=file(filename).read() 
     237                 
     238        self._datacentre_format = format 
     239        ''' 
     240        #If ingesting DIF 
     241        if self._datacentre_format == "DIF": 
     242            d=DIF(xml) 
     243            self.datasetID=d.entryID 
     244            self.datasetName = d.datasetTitle 
     245            self.datacentreName = d.datacentreName 
     246            self.metadataCreationDate=d.metadataCreationDate 
     247             
     248        #If ingesting MDIP             
     249        elif self._datacentre_format == "MDIP": 
     250            d=MDIP(xml)             
     251            self.datasetID=d.id 
     252            self.datasetName = d.datasetTitle 
     253            self.datacentreName = d.datacentreName 
     254            self.metadataCreationDate=d.metadataCreationDate 
     255             
     256        else: 
     257            raise TypeError, "Only handles DIF or MDIP here." 
     258        ''' 
     259         
     260        et=loadET(xml) 
     261        helper=nsdumb(et) 
     262        if self._datacentre_format=='DIF': 
     263            #return helper.getText(et,'Entry_ID') 
     264            self.datasetID=helper.getText(et,'Entry_ID') 
     265            self.datasetName = helper.getText(et,'Data_Set_Citation/Dataset_Title') 
     266            self.datacentreName = helper.getText(et,'Data_Center/Data_Center_Name/Short_Name') 
     267            self.metadataCreationDate=helper.getText(et,'DIF_Creation_Date') 
     268             
     269        elif self._datacentre_format == 'MDIP': 
     270            #return helper.getText(self.tree,'DatasetIdentifier') 
     271            self.datasetID=helper.getText(et,'DatasetIdentifier') 
     272            self.datasetName = helper.getText(et,'DatasetIdentifier') 
     273            self.datacentreName = helper.getText(et,'Distributor/DistributorName/DistributorNameName') 
     274            self.metadataCreationDate=helper.getText(et,'DateOfUpdateOfMetadata') 
     275        else: 
     276            raise TypeError,'idget does not support datatype [%s]'%dataType 
    17277 
    18278import unittest 
Note: See TracChangeset for help on using the changeset viewer.