source: TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/ExtractISO.py @ 6639

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/ExtractISO.py@6639
Revision 6639, 25.5 KB checked in by sdonegan, 10 years ago (diff)

Latest code that updates either NDG3 style or MEDIn style DB with all correct fields from MEDIN ISO updated

Line 
1
2from xml.etree import ElementTree as ET
3import logging,urllib,os,sys,inspect
4
5class ExtractISO:
6
7        def __init__(self,filenameIP,isoFormat):                               
8                               
9                self.inputXMLfile = filenameIP
10                self.isoFormatToExtract = isoFormat
11               
12                #show actual values extracted from the XML in logging.info
13                self.showXMLvalues = True
14               
15                logging.info("Have initialised ISO XML Extractor")
16               
17                #self.createISOdataStructure()
18               
19               
20        '''
21        Method to control re-writing of ISO xml with NDG redirect URL's
22        '''
23        def generateNDGredirectURL(self, ndgRedirectURL, xmlOutputFile):
24               
25                logging.info("Generating XML copy with URLS converted to NDG redirect URL's")
26               
27                self.redirectBaseURL = ndgRedirectURL
28               
29                rewriteIsoXml = self.changeElementUrlVal(self.isoModel.urlsToChange(), xmlOutputFile)
30               
31               
32                #sys.exit()
33               
34                return rewriteIsoXml
35       
36       
37       
38        '''
39        Method to map ISO variables to Discovery Database columns - use in PostgresDAO.py with getattr!
40       
41        returns a dictionary where key is
42    '''
43        def mapIsoFieldsToDBcolumns(self):
44               
45                return {'originalFormat':'original_format_name', \
46        'originalFormatVersion':'original_format_version',\
47        'datasetAbstract':'dataset_abstract', \
48        'resourceType':'resource_type_ts_vector', \
49        'topicCategory':'topic_category_ts_vector', \
50        'lineage':'lineage_ts_vector', \
51        'publicAccessLimitations':'limitations_public_access_ts_vector', \
52        'dataOriginator':'data_originator',\
53        'metadataUpdateDate':'dataset_metadata_update_date', \
54        'dataFormat':'original_format_name',
55        'createDate':'dataset_metadata_creation_date',
56        'publicationDate':'dataset_metadata_publication_date'}
57               
58               
59        '''
60                Method to match the columns found in mapIsoFieldsToDBcolumns to the postgres data types
61        '''
62        def mapDBcolumnsToIsoDataTypes(self):
63               
64                return {'original_format_name':'text', \
65        'original_format_version':'text',\
66        'dataset_abstract':'text', \
67        'resource_type_ts_vector':'tsvector', \
68        'topic_category_ts_vector':'tsvector', \
69        'lineage_ts_vector':'tsvector', \
70        'limitations_public_access_ts_vector':'tsvector', \
71        'data_originator':'tsvector',\
72        'dataset_metadata_update_date':'timestamp', \
73        'original_format_name':'text',
74        'dataset_metadata_creation_date':'timestamp',
75        'dataset_metadata_publication_date':'timestamp'}
76       
77               
78        '''
79        Simple method to allow return information on success of extraction ( __init__ method cannot return anything so use this method)
80        '''
81        def createISOdataStructure(self):
82               
83                logging.info("")
84                logging.info("********************************************************************************************************************************************")
85                logging.info("****************** Creating ISO data structure from " + self.inputXMLfile + "****************** ")
86                logging.info("********************************************************************************************************************************************")
87                logging.info("")
88               
89               
90                self.root = self.getIsoXML(self.inputXMLfile)
91               
92                self.isoFileLocation = self.inputXMLfile       
93               
94                #self.root = self.getIsoXML('/misc/glue1/sdonegan/NDG3_workspace/buildouts/oai_document_ingester_MEDIN/ingestAutomation-upgrade/OAIBatch//data/NEODC/stub_iso/neodc.nerc.ac.uk__stubISO__dataent_11658383444211836_DIF.xml')
95               
96                if self.root is None:
97                        logging.error("Detected possible problem with input xml - cannot parse it!")
98                        return False
99               
100                #choose the ISO xpath definition class depending on format profile required
101                self.importISOxmlDefinition(self.isoFormatToExtract)
102                                                       
103                #get all the required information from the chosen xpath definition class
104                self.datasetID = self.getElementVal(self.isoModel.datasetID())
105               
106                self.datasetName = self.getElementVal(self.isoModel.dataSetName())
107               
108                self.datasetAbstract = self.getElementVal(self.isoModel.dataSetAbstract())
109               
110                self.datasetID = self.getElementVal(self.isoModel.datasetID())
111               
112                self.revisionDate = self.getElementVal(self.isoModel.metadataRevisionDate())
113               
114                self.createDate = self.getElementVal(self.isoModel.metadataCreationDate())
115                               
116                self.datasetName = self.getElementVal(self.isoModel.dataSetName())             
117               
118                self.boundingDates = self.getElementVal(self.isoModel.boundingDates())
119               
120                self.boundingDatesRange = self.boundingDateRange(self.boundingDates)   
121               
122                self.originalFormat = self.getElementVal(self.isoModel.originalFormat())
123               
124                self.authors = self.getElementVal(self.isoModel.authors())
125                               
126                self.datacentreName = self.getElementVal(self.isoModel.dataCentreName())
127               
128                self.parameters = self.getElementVal(self.isoModel.parameters()) 
129               
130                self.keywords = self.getElementVal(self.isoModel.keywords())
131               
132                self.keywordsList = self.listify(self.keywords)
133               
134                self.boundingBoxCoordinates = self.getElementVal(self.isoModel.coordinates())                           
135               
136                #These are the MEDIN requested extra fields - make optional
137                try:
138                        self.originalFormatVersion = self.getElementVal(self.isoModel.originalFormatVersion())
139                except:
140                        self.originalFormatVersion = None
141               
142                try:
143                        self.publicationDate = self.getElementVal(self.isoModel.metadataPublicationDate())
144                except:
145                        self.publicationDate = None
146                       
147                try:
148                        self.resourceType = self.getElementVal(self.isoModel.resourceType())
149                except:
150                        self.resourceType = None
151               
152                try:
153                        self.topicCategory = self.getElementVal(self.isoModel.topicCategory())
154                except:
155                        self.topicCategory = None
156               
157                try:
158                        self.lineage = self.getElementVal(self.isoModel.lineage())
159                except:
160                        self.lineage = None
161               
162                try:
163                        self.publicAccessLimitations = self.getElementVal(self.isoModel.publicAccessLimitations())
164                except:
165                        self.publicAccessLimitations = None
166                       
167                try:
168                        self.dataOriginator= self.getElementVal(self.isoModel.dataOriginator())
169                       
170                except:
171                        self.dataOriginator = None
172               
173                try:
174                        self.dataFormat = self.getElementVal(self.isoModel.originalFormat())
175                except:
176                        self.dataFormat = None
177               
178                try:
179                        self.metadataUpdateDate = self.getElementVal(self.isoModel.metadataUpdateDate())
180                except:
181                        self.metadataUpdateDate = None
182                       
183                       
184                try:
185                        self.originalFormatName = self.getElementVal(self.isoModel.originalFormat())
186                except:
187                        self.originalFormatName = None
188                       
189                try:
190                        self.originalFormatVersion = self.getElementVal(self.isoModel.originalFormatVersion())
191                except:
192                        self.originalFormatVersion = None
193                       
194               
195                logging.info("")
196                logging.info(" ****************** Completed rendering ISO xml into data structure! ****************** ")
197                logging.info("")
198               
199                return True
200       
201       
202        '''
203        Method to generate a simple list object from a compound list set
204        '''
205        def listify(self,listObject):
206               
207                list = []
208               
209                for outer in listObject:
210                        for inner in outer:                             
211                                list.append(inner)
212                                               
213                return list
214               
215        '''
216        Method to return start and end dates from a sequence of dates such as that found returned using the xpath defn from boundingDates
217        '''
218        def boundingDateRange(self,boundingDatesList):
219               
220                #generate a simple list of all dates
221                allDates = []
222                returnDates = {}
223               
224                #remember, need to sort out whether there was a start and end date in the first place, or just one so can copy values over
225                if len(boundingDatesList) == 1:
226                        logging.info("Only 1 set of start and stop dates, so setting range to this..")
227                        returnDates['start'] = boundingDatesList[0]['start']
228                        returnDates['end'] = boundingDatesList[0]['end']
229                       
230                        #convert None to 'None'
231                        for date in returnDates.keys():
232                                if returnDates[date] is None:
233                                        returnDates[date] = 'None'
234                       
235                        return returnDates
236               
237                for outer in boundingDatesList:
238                        for inner in outer.keys():
239                                if outer[inner] is not None:
240                                        if outer[inner] != 'None':
241                                                #some other test here to ensure proper date object
242                                                allDates.append(outer[inner])
243                                               
244                               
245                #min and max seem to work for now (to get it working) - assuming proper dateformat (restrict to YYYY-MM-DD for now)
246                #TODO: use datetime library to do this properly         
247                returnDates['start'] = min(allDates)
248                returnDates['end'] = max(allDates)
249               
250                return returnDates
251       
252       
253               
254        '''
255        Method to import specific ISO xpath definition class depending on the profile used
256        '''
257        def importISOxmlDefinition(self,format):
258               
259                '''
260                MEDIN Profile v2.3 (date? - MEDIN upgrade dev)
261                '''
262               
263                logging.info("Format chosen: " + format)
264               
265               
266               
267                #Dynamically import module of correct profile...
268                import_string = "from " + format + " import " + format + " as iso"
269               
270                try:
271                        exec import_string
272                except:
273                        logging.error("Could not import xpath class for: " + format)
274                        sys.exit()
275               
276                self.isoModel = iso()
277               
278               
279        '''
280        Method to govern the changing of an element value (in the first instance change a url to a NDG redirect URL
281        '''
282        def changeElementUrlVal(self,keyMethod,outputFile):
283               
284       
285                logging.info("******************************************************************************************")
286                logging.info("Extracting xpath information for data extraction type (to change URL..):" + keyMethod[0])
287                logging.info("******************************************************************************************")
288                               
289               
290                #first need to interpret the contents of the tuple we've been passed everything is a dictionary in the tuple apart from element 0:
291                #build a map of it - do this as a dictionary with the key as the position in the tuple and the value as the element val, be it str or dictionary key
292                dataStruct = self.interpretTuple(keyMethod)
293                cnt = 0
294               
295                #this is similar to getElementVal - but no interest in ordering or returning the actual value..
296                for i in dataStruct.keys()[1:]:
297                                               
298                        thisData = keyMethod[i][dataStruct[i]]
299                                                               
300                        #is dicionary a dependant value or straight xpath?
301                        if 'baseXpath' in thisData.keys():
302                                logging.info("Extracting xml using COMPLEX dependant method for xpath def: " + str(cnt))                       
303                                self.changeDependantURLElementVal(thisData['baseXpath'],thisData['elValXpath'],thisData['depValXpath'],thisData['depVal'])                             
304                                                               
305                        if 'xpath' in thisData.keys():         
306                                logging.info("Extracting xml using SIMPLE method for xpath def: " + str(cnt))                                           
307                                self.changeSimpleURLElementVal(thisData['xpath'])       
308                                                                               
309                #having returned the completed xml tree... write it to the OP file dictated..
310                try:
311                        #rewrite this back into the xml doc                             
312                        self.etree.write(outputFile)
313                        logging.info("Have successfully generated new ISO file with rewritten urls to NDG redirect format!")
314                       
315                        return True
316               
317                except:
318                        logging.error("Could not rewrite NDG url ISO xml to; " + outputFile)
319                       
320                        return False
321               
322               
323        '''
324        Method to change an ISO element val - simple xpath value
325        '''
326        def changeSimpleURLElementVal(self, xpath):
327               
328                #Note using single path namespath appender rather than list version.. (keeps it simpler)       
329                xpathNS = self.appendNameSpace(xpath)           
330               
331                resElementVal = []
332               
333                try:   
334                        rootEl = self.root.findall(xpathNS)
335                       
336                except:
337                        logging.error("Could not find element for this xpath: " + xpath)                       
338                       
339                                               
340                #use a text 'None' rather than a None type                     
341                for elVal in rootEl:
342                        if elVal is None: 
343                                originalUrl = 'None' 
344                        else:
345                                try:                   
346                                        originalUrl = elVal.text       
347                                        redirectURL = self.redirectBaseURL + originalUrl + '&docID=' + urllib.quote(self.datasetID[0][0]) + '&docTitle=' + urllib.quote(self.datasetName[0][0])
348                               
349                                        #reassign...
350                                        elVal.text = redirectURL                                       
351                                        logging.info("Have successfuly rewritten ndg redirect URL: " + redirectURL)
352                                       
353                                except:
354                                        logging.error("Could not change original (simple) url!")
355               
356                       
357                #no need to return anything -if we rewrite the doc, any successful changes will be incorporated, otherwise will be ignored
358       
359        '''
360        Method to change an ISO element val - compound dependant xpath values
361        '''
362        def changeDependantURLElementVal(self,baseXpath,elXpath,depXpath,depValReqd):
363               
364                #Note using single path namespath appender rather than list version.. (keeps it simpler)       
365                baseXpath = self.appendNameSpace(baseXpath)
366                               
367                #for path in baseXpaths:
368                try:                           
369                        rootEl = self.root.findall(baseXpath) #returns an elementree object of elements in a list                               
370                except:
371                        logging.error("Could not find element for this xpath: " + baseXpath)
372                        return 'None'
373                       
374                for el in rootEl:
375                        thisElXpth = self.appendNameSpace(elXpath)
376                                                               
377                        thisEl = self.doFindall(el,thisElXpth)
378                               
379                        #if there's a value for the actual xpath we want, go and get the dependant value
380                        if thisEl != 'None':
381                                       
382                                elVal = thisEl[0]
383                                elValTxt = elVal.text #NOTE take first one as we expect this to be the value we want
384                                                                       
385                                thisEldepXpth = self.appendNameSpace(depXpath)                                 
386                                thisDepEl = self.doFindall(el,thisEldepXpth)                                                           
387                                       
388                                if thisDepEl != 'None':
389                                                                               
390                                        depVal = thisDepEl[0].text
391                                                                       
392                                        if depVal == depValReqd:
393                                               
394                                                try:
395                                                        originalUrl = elValTxt                                         
396                                                        redirectURL = self.redirectBaseURL + originalUrl + '&docID=' + urllib.quote(self.datasetID[0][0]) + '&docTitle=' + urllib.quote(self.datasetName[0][0])
397                                                                                       
398                                                        #reassign...
399                                                        elVal.text = redirectURL                                                                                       
400                                                        logging.info("Have successfuly rewritten ndg redirect URL: " + redirectURL)
401                                                       
402                                                except:
403                                                        logging.error("Could not change original (complex) url!")
404                                       
405                                                                                                                       
406                #no need to return anything -if we rewrite the doc, any successful changes will be incorporated, otherwise will be ignored
407               
408       
409        '''
410        Method to initially interpret the xpath dictionary type passed
411        '''
412        def interpretTuple(self,keyMethod):
413               
414                dataStruct = {}
415                counter=0
416                for i in keyMethod:
417                        if type(i) is dict:
418                               
419                                #loop through the top level (remember its a dictionary of dictionaries!)
420                                for j in i.keys():                             
421                                        dataStruct[counter]=j
422                       
423                        #Only other data type present should be a string
424                        if type(i) is str:
425                                dataStruct[counter] = i
426                               
427                        counter = counter + 1
428                               
429                return dataStruct
430       
431               
432        '''
433        Method to aid passing and extraction info from complex xpath tuples
434       
435        Will work out whether complex or simple xpath extraction required depending on type of xpath method sent
436       
437        If 'order' key present then will return a dictionary of values with the extracted value using the specified key.
438       
439        '''
440        def getElementVal(self,keyMethod):
441               
442                #develop handler method to simplify
443                returnValList=[]                               
444                returnVal = 'None'
445               
446                logging.info("******************************************************************************************")
447                logging.info("Extracting xpath information for data extraction type:" + keyMethod[0])
448                logging.info("******************************************************************************************")
449                               
450                showValue = self.showXMLvalues
451               
452                #first need to interpret the contents of the tuple we've been passed everything is a dictionary in the tuple apart from element 0:
453                #build a map of it - do this as a dictionary with the key as the position in the tuple and the value as the element val, be it str or dictionary key
454                dataStruct = self.interpretTuple(keyMethod)
455                '''
456                dataStruct = {}
457                counter=0
458                for i in keyMethod:
459                        if type(i) is dict:
460                               
461                                #loop through the top level (remember its a dictionary of dictionaries!)
462                                for j in i.keys():                             
463                                        dataStruct[counter]=j
464                       
465                        #Only other data type present should be a string
466                        if type(i) is str:
467                                dataStruct[counter] = i
468                               
469                        counter = counter + 1
470                '''
471               
472                #now iterate through the key list in dataStruct but miss First one (as its a name val!)                 
473                valueList = []
474                ordering = False
475               
476                cnt = 1
477               
478                for i in dataStruct.keys()[1:]:
479                                               
480                        thisData = keyMethod[i][dataStruct[i]]
481                                                               
482                        #is dicionary a dependant value or straight xpath?
483                        if 'baseXpath' in thisData.keys():
484                                logging.info("Extracting xml using COMPLEX dependant method for xpath def: " + str(cnt))                       
485                                returnVal = self.returnDependantElementVal(thisData['baseXpath'],thisData['elValXpath'],thisData['depValXpath'],thisData['depVal'],showValue)                           
486                                valueList.append(returnVal)
487                                                               
488                        if 'xpath' in thisData.keys():         
489                                logging.info("Extracting xml using SIMPLE method for xpath def: " + str(cnt))                                           
490                                returnVal =  self.returnSimpleElementVal(thisData['xpath'],showValue)                                                           
491                                valueList.append(returnVal)
492                                                               
493                        #is there any ordering info required - if so, order the return list according to the ordering tuple
494                        if 'order' in keyMethod[i].keys():
495                                logging.info("Returning a dictionary of paired values as ordering requested for xpath (number of xpath defs MUST match ordering vals available")                       
496                                ordering = True                         
497                                orderingList = thisData
498                               
499                        else:
500                                logging.info("Returning a simple list of values for xpath def: " + str (cnt))
501                               
502                        cnt = cnt + 1
503                       
504                #if ordering is required, create a corresponding dictionary of ordered values                                   
505                if ordering:
506                       
507                        #logging.INFO("Ordering data by specified order information!")
508                        logging.info("ordering information now!")
509                       
510                        '''FIRST need to group information together in correct order (i.e. elementtree groups all starts in one list, then all ends etc
511                        i.e. [[start1,start2],[end1,end2]] to [[start1,end1],[start2,end2]]
512                        '''
513                        #import pdb
514                        #pdb.set_trace()
515                        #check that number of number of elements in ordering list is not less than number of items in list to be ordered!
516                        #if multiple sets to be ordered, check numbers and return as dictionary
517                        checkCompLnth = len(valueList[0])
518                        for list in valueList:
519                                if len(list) != checkCompLnth:
520                                        logging.error("Sub component lists are of unequal length - CANNOT order!!")
521                                        return 'None'
522                               
523                        #outer loop should be the number of elements in the sublists..
524                        outer = []
525                        for localPos in range(0,checkCompLnth):
526                                inner=[]
527                                #inner loop should be the number of lists corresponding to repeating subelements                       
528                                for listPos in range(0,len(valueList)):
529                                       
530                                                inner.append(valueList[listPos][localPos])
531                                #append to outer loop
532                                outer.append(inner)                                                     
533                       
534                        for returnedList in outer:
535                               
536                                #create a disctionary for this round (will append it later to the return version)
537                                orderedValsSub = {}
538                                                                               
539                                if len(returnedList) != len(orderingList):
540                                        logging.error("Ordering List length does not match length of list to be ordered! (NOTE: can only order where lengths match!)")
541                                        returnValList.append('None')
542                               
543                                else:           
544                                        #go through valueList and extract values in correct position and build dictionary
545                                        for i in orderingList.keys():
546                                               
547                                                orderedValsSub[i] = returnedList[orderingList[i]-1] # remember there's an offset as '0' not used in these vals
548                               
549                               
550                                        returnValList.append(orderedValsSub)
551                       
552                        return returnValList
553                       
554                else:
555                        return valueList
556                       
557                       
558        '''
559        Method to return a list of values of an element value dependant on another element value held within the local tree
560        i.e. return a specific string val depending on a local code val in ISO
561       
562        if element exists and any dependant value present matches the expected value, the element value is returned as part of a list,
563        otherwise an empty list is returned
564        '''
565        def returnDependantElementVal(self,baseXpath,elXpath,depXpath,depValReqd,showValue=False):
566                       
567                #Note using single path namespath appender rather than list version.. (keeps it simpler)       
568                baseXpath = self.appendNameSpace(baseXpath)
569               
570                resDependantVal = []
571               
572                #for path in baseXpaths:
573                try:                           
574                        rootEl = self.root.findall(baseXpath) #returns an elementree object of elements in a list                               
575                except:
576                        logging.error("Could not find element for this xpath: " + baseXpath)
577                        return 'None'
578                       
579                for el in rootEl:
580                        thisElXpth = self.appendNameSpace(elXpath)
581                                                               
582                        thisEl = self.doFindall(el,thisElXpth)
583                               
584                        #if there's a value for the actual xpath we want, go and get the dependant value
585                        if thisEl != 'None':
586                                       
587                                elVal = thisEl[0].text #NOTE take first one as we expect this to be the value we want
588                                                                       
589                                thisEldepXpth = self.appendNameSpace(depXpath)                                 
590                                thisDepEl = self.doFindall(el,thisEldepXpth)                                                           
591                                       
592                                if thisDepEl != 'None':
593                                                                               
594                                        depVal = thisDepEl[0].text
595                                                                       
596                                        if depVal == depValReqd:
597                                               
598                                                if showValue is True:
599                                                        logging.info("")
600                                                        logging.info("          Element Value: " + elVal)
601                                                        logging.info("")
602                                               
603                                                resDependantVal.append(elVal)
604                                                                                                                                                       
605                return resDependantVal
606       
607        '''
608        Method to extract a value from the doc using a simple xpath.  If no element found or no data present then None is returned
609        '''
610        def returnSimpleElementVal(self,xpath,showValue=False):
611               
612                #Note using single path namespath appender rather than list version.. (keeps it simpler)       
613                xpathNS = self.appendNameSpace(xpath)           
614               
615                resElementVal = []
616               
617                try:   
618                        rootEl = self.root.findall(xpathNS)
619                       
620                except:
621                        logging.error("Could not find element for this xpath: " + xpath)                       
622                        return ['None']
623                                               
624                #use a text 'None' rather than a None type
625               
626                for elVal in rootEl:
627                        if elVal is None:
628                                resElementVal.append('None')
629                        else:
630                                value = elVal.text
631                                if (showValue is True) and (value is not None):
632                                        logging.info("")
633                                        logging.info("          Element Value: " + value)
634                                        logging.info("")
635                                       
636                                resElementVal.append(value)
637                '''     
638                if rootEl[0].text is None:                                     
639                        resElementVal.append('None')
640                else:
641                        for el in rootEl:                                       
642                                resElementVal.append(el.text)   
643                               
644                                       
645                '''
646               
647                return resElementVal
648                               
649       
650        '''
651        Method to run an elementtree findall on ns appended path in the supplied element and return list
652        returns None if nothing found
653        '''
654        def doFindall(self,el,thisElXpth):
655                               
656                try:
657                        thisElXpthEl = el.findall(thisElXpth)
658                       
659                        if len(thisElXpthEl) == 0:
660                                thisElXpthEl = 'None'
661                except:
662                        thisElXpthEl = 'None'
663               
664               
665                return thisElXpthEl
666               
667               
668        '''
669        Method to extract actual value from xml doc - expects a list of namespace qualified xpaths and will return corresponding list of values
670        '''
671        def getXmlVal(self,paths):
672               
673                xmlVals = []
674                               
675                for path in paths:
676                        try:
677                                xmlVals.append(self.root.find(path).text)                       
678                        except:
679                                logging.error("Could not extract value for xpath: " + path)
680                                xmlVals.append('null')
681                               
682                return xmlVals                                 
683               
684        '''
685        Method to hold a dictionary linking namespace prefixes to URLs
686        '''
687        def isoNameSpaces(self):
688               
689                isoNs = {'gmd':'http://www.isotc211.org/2005/gmd','gco':'http://www.isotc211.org/2005/gco',
690                                'gmx':'http://www.isotc211.org/2005/gmx','gml':'http://www.opengis.net/gml/3.2',
691                                'none':'','gts':'http://www.isotc211.org/2005/gts','gsr':'http://www.isotc211.org/2005/gsr',
692                                'gss':'http://www.isotc211.org/2005/gss'
693                                }
694               
695                return isoNs
696       
697       
698        '''
699        Method to return DEFAULT namespace in elementtree format of ISO profile used (i.e. should be gmd)
700        (to deal with those elements with no prefix)
701        '''
702        def defaultIsoNamespace(self):
703                return 'gmd'
704               
705       
706       
707        '''
708        Method to extract root element of XML file specified using elementtree
709        '''     
710        def getIsoXML(self,file):
711               
712                logging.info("Getting xml root element")
713               
714                #parse the xml with elementtree
715                self.etree=ET.parse(file)
716                root=self.etree.getroot() # should be the "gmd:MD_Metadata" element
717               
718                #avoid ns0 and ns1 etc etc namespaces when rewriting this ET
719                logging.info("Sorting out namespaces so can properly rewrite ISO xml..")
720                for ns in self.isoNameSpaces().keys():         
721                        if ns != 'None':                                               
722                                ET._namespace_map[self.isoNameSpaces()[ns]] = ns
723               
724                               
725                #check root element is an ISO one - use elementtree appended namespace..
726                if root.tag != '{http://www.isotc211.org/2005/gmd}MD_Metadata':
727                        logging.error("XML document does not appear to be ISO (not gmd:MD_Metadata)!!")                 
728                        return None
729       
730                return root
731               
732               
733        '''
734        Method to convert the given xpath list to a namespace abbreviated version so elementtree can handle it (grrr.). 
735        Will return a list of corresponding namespace qualified xpaths - if errors a 'null' will be placed.
736        '''
737        def appendNameSpaceList(self,paths):
738               
739                nameSpaceAppendedPaths = []
740               
741               
742                for path in paths:             
743                       
744                        pathElements = path.split('/')
745                       
746                        #note due to crappy elementtree have to avoid initial "/"
747                        count = 0
748                        for element in pathElements:
749                               
750                                try:                                   
751                                        if ':' in element:                                             
752                                                splitElement = element.split(':')
753                                                nsPrefix,nsElement = splitElement[0],splitElement[1]
754                                        else:
755                                                #use default namespace                                         
756                                                nsPrefix = self.defaultIsoNamespace()
757                                                nsElement = element
758                                       
759                                        if count == 0:
760                                               
761                                                #appendedPath = self.returnNS() + element
762                                                appendedPath = '{' + self.isoNameSpaces()[nsPrefix] +'}' + nsElement
763                                        else:
764                                               
765                                                appendedPath = appendedPath + '/{' + self.isoNameSpaces()[nsPrefix] +'}' + nsElement
766                                       
767                                        count += 1
768                                except:
769                                        appendedPath = 'null'
770                                        logging.error("Could not change to elementtree ns xpath")
771                                                       
772                        #clear up any blank namespace prefixes
773                        appendedPath = appendedPath.replace('{}','')
774                       
775                        nameSpaceAppendedPaths.append(appendedPath)
776
777                return nameSpaceAppendedPaths
778       
779        '''
780        Method to convert the given xpath to a namespace abbreviated version so elementtree can handle it (grrr.). 
781        Will return an equivalent namespace qualified xpath - if errors a 'null' will be placed.
782        '''
783        def appendNameSpace(self,path):
784               
785                nameSpaceAppendedPath = ''
786               
787                pathElements = path.split('/')
788                       
789                #note due to crappy elementtree have to avoid initial "/"
790                count = 0
791                for element in pathElements:
792                               
793                        try:                                   
794                                if ':' in element:                                             
795                                        splitElement = element.split(':')
796                                        nsPrefix,nsElement = splitElement[0],splitElement[1]
797                                else:
798                                        #use default namespace                                         
799                                        nsPrefix = self.defaultIsoNamespace()
800                                        nsElement = element
801                                       
802                                if count == 0:
803                                               
804                                        #appendedPath = self.returnNS() + element
805                                        appendedPath = '{' + self.isoNameSpaces()[nsPrefix] +'}' + nsElement
806                                else:                                           
807                                        appendedPath = appendedPath + '/{' + self.isoNameSpaces()[nsPrefix] +'}' + nsElement
808                                       
809                                count += 1
810                        except:
811                                appendedPath = 'null'
812                                logging.error("Could not change to elementtree ns xpath")
813                                                       
814                #clear up any blank namespace prefixes
815                nameSpaceAppendedPath = appendedPath.replace('{}','')
816               
817                return nameSpaceAppendedPath
Note: See TracBrowser for help on using the repository browser.