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

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

Commit of code that updates successfully MEDIN ISO as well as GCMD DIF into NDG3 style postgres DB..

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