source: mauRepo/MolesManager/trunk/src/libs/migration/processor/commons.py @ 8445

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/MolesManager/trunk/src/libs/migration/processor/commons.py@8445
Revision 8445, 39.0 KB checked in by mnagni, 7 years ago (diff)

Complete - # 22489: CEDA Observation Collection - phenomenonTime
 http://team.ceda.ac.uk/trac/ceda/ticket/22489
Complete - # 22488: CEDA Observation Collection - Geographical Extent
 http://team.ceda.ac.uk/trac/ceda/ticket/22488

Line 
1'''
2BSD Licence
3Copyright (c) 2012, Science & Technology Facilities Council (STFC)
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without modification,
7are permitted provided that the following conditions are met:
8
9    * Redistributions of source code must retain the above copyright notice,
10        this list of conditions and the following disclaimer.
11    * Redistributions in binary form must reproduce the above copyright notice,
12        this list of conditions and the following disclaimer in the documentation
13        and/or other materials provided with the distribution.
14    * Neither the name of the Science & Technology Facilities Council (STFC)
15        nor the names of its contributors may be used to endorse or promote
16        products derived from this software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29Created on 15 Nov 2011
30
31@author: mnagni
32'''
33from ea_model.moles3_4.utilities.mo_responsiblepartyinfo import MO_ResponsiblePartyInfo
34from httplib import HTTPConnection
35from xml.etree.ElementTree import XML, tostring
36import time, datetime
37from libs.migration.exception.exceptions import NoDataLineage
38from hashlib import md5
39from xml.sax.saxutils import unescape, escape
40import html5lib
41from html5lib import treebuilders
42from ea_model.moles3_4.result.mo_onlineresource import MO_OnlineResource
43from ea_model.iso_19115_2006_metadata_corrigendum.reference_system_information.md_identifier import MD_Identifier
44from ea_model.iso_19115_2006_metadata_corrigendum.identification_information.md_keywords import MD_Keywords
45from ea_model.iso_19103_2005_schema_language.basic_types.primitive.date_and_time.datetime import DateTime
46from ea_model.iso_19103_2005_schema_language.basic_types.primitive.date_and_time.date import Date
47from ea_model.iso_19108_2006_temporal_schema.temporal_reference_system.tm_position import TM_Position
48from ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_instant import TM_Instant
49from ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_period import TM_Period
50from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_address import CI_Address
51from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_onlineresource import CI_OnlineResource
52from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_telephone import CI_Telephone
53from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_contact import CI_Contact
54from ea_model.moles3_4.utilities.mo_individual import MO_Individual
55from ea_model.moles3_4.utilities.mo_organisation import MO_Organisation
56from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_date import CI_Date
57from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_citation import CI_Citation
58from ea_model.iso_19115_2006_metadata_corrigendum.constraint_information.md_constraints import MD_Constraints
59from ea_model.iso_19115_2006_metadata_corrigendum.constraint_information.md_legalconstraints import MD_LegalConstraints
60from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_responsibleparty import CI_ResponsibleParty
61from ea_model.iso_19115_2006_metadata_corrigendum.metadata_entity_set_information.md_metadata import MD_Metadata
62from ea_model.iso_19115_2006_metadata_corrigendum.data_quality_information.dq_conformanceresult import DQ_ConformanceResult
63from ea_model.iso_19115_2006_metadata_corrigendum.extent_information.ex_geographicboundingbox import EX_GeographicBoundingBox
64from ea_model.iso_19115_2006_metadata_corrigendum.data_quality_information.dq_element import DQ_Element
65from ea_model.ceda_metadatamodel.ceda_project.ceda_project import CEDA_Project
66from ea_model.ceda_metadatamodel.ceda_utilities.ceda_review import CEDA_Review
67from ea_model.ceda_metadatamodel.ceda_acquisition.ceda_acquisition import CEDA_Acquisition
68from ea_model.ceda_metadatamodel.ceda_observationprocess.ceda_compositeprocess import CEDA_CompositeProcess
69from ea_model.ceda_metadatamodel.ceda_acquisition.ceda_instrument import CEDA_Instrument
70from ea_model.ceda_metadatamodel.ceda_computation.ceda_processing import CEDA_Processing
71from ea_model.ceda_metadatamodel.ceda_result.ceda_result import CEDA_Result
72import datetime
73
74base = '/exist/rest/atoms'
75
76DS_pUBLISHED = 'published'
77DS_WORKING = 'working'
78DS_PUBLISHED = 'Published'
79DOC_STATUS = (DS_pUBLISHED, DS_WORKING, DS_PUBLISHED)
80
81DT_DEPLOYMENTS = 'deployments'
82DT_DATA_ENTITIES = 'data_entities'
83DT_DEPLOYMENT_DATA = 'deployment_data'
84DT_DATA_GRANULES = 'data_granules'
85DOC_TYPES = (DT_DEPLOYMENTS, DT_DATA_ENTITIES, DT_DEPLOYMENT_DATA, DT_DATA_GRANULES)
86
87DO_BADC = 'badc.nerc.ac.uk'
88DO_NEODC = 'neodc.nerc.ac.uk'
89DO_UKSSDC = 'ukssdc.ac.uk'
90
91CEDA = 'Centre for Environmental Data Archive'
92docOwners = (DO_BADC, DO_NEODC, DO_UKSSDC)
93
94atomNS = "{http://www.w3.org/2005/Atom}"
95existNS = "{http://exist.sourceforge.net/NS/exist}"
96molesNS = "{http://ndg.nerc.ac.uk/schema/moles2beta}"
97htmlNS = "{http://www.w3.org/1999/xhtml}"
98georssNS="{http://www.georss.org/georss/10}"
99gmlNS="{http://www.opengis.net/gml}"
100date_format = '%Y-%m-%d'
101datetime_format = date_format + 'T%H:%M:%SZ'
102ihost = 'bora.badc.rl.ac.uk'
103iport = '8080'
104
105linkMarkers = ['Deployment', 'DOWNLOAD', 'DOCUMENTATION', 'ACCESS', 'LOGO', 'ACTIVITY', 'DPT', 'OBS']
106
107#MD_Identifier codes
108MD_CODE_MOLES2_CITATION = 'ceda_moles2_citation'
109
110htmlParser = html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("etree"), namespaceHTMLElements=False)
111
112def calculateHash(text):
113    """
114        Returns an md5 hexadecimal representation of the given text
115        @param text: the string to encode
116        @return: the hexadecimal md5 value of the given text
117    """
118    encoder = md5()
119    encoder.update(text)
120    return encoder.hexdigest()
121
122def buildExistDocPath(docStatus, docType, docOwner, docName):
123    '''
124        @param docStatus: one value from commons.docStatus
125        @param docType: one value from commons.docTypes
126        @param docOwner: one value from commons.docOwners
127        @param docName: one value from commons.docOwners       
128    '''       
129    return '%s/%s' % (buildExistOwnerPath(docStatus, docType, docOwner), docName)
130
131def buildExistOwnerPath(docStatus, docType, docOwner):
132    '''
133        @param docStatus: one value from commons.docStatus
134        @param docType: one value from commons.docCollections
135        @param docOwner: one value from commons.docOwners
136    '''       
137    return '%s/%s' % (buildExistTypePath(docStatus, docType), docOwner)
138
139def buildExistTypePath(docStatus, docType):
140    '''
141        @param docStatus: one value from commons.docStatus
142        @param docType: one value from commons.docCollections
143    '''       
144    return '%s/%s' % (buildExistStatusPath(docStatus), docType)
145
146def buildExistStatusPath(docStatus):
147    '''
148        @param docStatus: one value from commons.docStatus
149    '''       
150    return '/exist/rest/atoms/%s' % (docStatus)
151
152def getAtomDocumentByMO(migrationObject):
153    if migrationObject is None:
154        raise Exception("migrationObject is None")
155    mo_typeDict = {'DeploymentsMigration': DT_DEPLOYMENTS, 'DataEntityMigration': DT_DATA_ENTITIES, 'DeploymentDataMigration': DT_DEPLOYMENT_DATA}     
156    return getAtomDocumentAsElementtree(migrationObject.doc_status, mo_typeDict[type(migrationObject).__name__], migrationObject.doc_owner, migrationObject.doc_name)
157
158def getAtomDocumentHashByMO(migrationObject):
159    if migrationObject is None:
160        raise Exception("migrationObject is None")   
161    mo_typeDict = {'DeploymentsMigration': DT_DEPLOYMENTS, 'DataEntityMigration': DT_DATA_ENTITIES, 'DeploymentDataMigration': DT_DEPLOYMENT_DATA}     
162    text = _getAtomDocumentAsText(migrationObject.doc_status, mo_typeDict[type(migrationObject).__name__], migrationObject.doc_owner, migrationObject.doc_name)
163    return calculateHash(text)
164
165def getAtomDocumentHash(docStatus, docType, docOwner, docName):
166    source = buildExistDocPath(docStatus, docType, docOwner, docName)
167    text = _getDocument(source)
168    return calculateHash(text)
169
170def hasMOBeenProcessed(migrationObject):
171    '''
172        Checks if a migration object has been already processed.
173        @param migrationObject: an instance of DataEntityMigration or DeploymentsMigration
174        @return True if has been processed, otherwise False
175    '''
176    if migrationObject is None:
177        return False
178   
179    if not hasattr(migrationObject, 'doc_hash'):
180        return False
181    else:
182        if migrationObject.doc_hash is None:
183            return False
184       
185    return True
186
187def hasMOSameHash(migrationObject):
188    '''
189        Checks if a migration object has changed.
190        @param migrationObject: an instance of DataEntityMigration or DeploymentsMigration or DeploymentDataMigration
191        @return True if the hash of the actual document is the same of the migrationObject, otherwise False
192    '''
193    if not hasMOBeenProcessed(migrationObject):
194        return False
195    return getAtomDocumentHashByMO(migrationObject) == migrationObject.doc_hash
196
197def getAtomDocumentByType(migrationObject, docType):
198    if migrationObject is None:
199        raise Exception("migrationObject is None")   
200    return getAtomDocumentAsElementtree(migrationObject.doc_status, docType, migrationObject.doc_owner, migrationObject.doc_name)
201
202def _getAtomDocumentAsText(docStatus, docType, docOwner, docName):
203    source = buildExistDocPath(docStatus, docType, docOwner, docName)
204    return _getDocument(source)
205
206def getAtomDocumentAsElementtree(docStatus, docType, docOwner, docName):
207    source = buildExistDocPath(docStatus, docType, docOwner, docName)
208    return _getXMLDocument(source)
209
210def _getXMLDocument(source):
211    return XML(_getDocument(source))
212
213def stringToTimestamp(timestring):
214    '''
215        Return a timestamp such as is returned by time.time().
216        @param timestring: a time string formatted as '%Y-%m-%dT%H:%M:%SZ'
217    '''   
218    return datetime.datetime.fromtimestamp(time.mktime(time.strptime(timestring, datetime_format)))
219
220def isoDateStringToTimeDate(datestring):
221    '''
222        Return a datatime.datatime instance.
223        @param datestring: a date string formatted as '%Y-%m-%d'
224    '''
225    return datetime.datetime.strptime(datestring, date_format)
226
227def isoDateTimeStringToTimeDate(timestring):
228    '''
229        Return a datatime.datatime instance.
230        @param timestring: a time string formatted as '%Y-%m-%dT%H:%M:%SZ'
231    '''
232    return datetime.datetime.strptime(timestring, datetime_format)
233
234def _getDocument(source):
235    conn = HTTPConnection(host = ihost, port = iport)
236    conn.connect()
237    req = conn.request('GET', source)
238    res = conn.getresponse()
239    xmlDoc = res.read()
240    '''
241    print (xmlDoc)
242    '''
243    conn.close()
244    return xmlDoc
245
246def _returnNotNoneText(element):
247    if element is None:
248        return None
249    return element.text
250
251def findMolesCreationDate(resourceXML):
252    creationDate = resourceXML.find('%sentity/%smolesISO/%screated' % (molesNS, molesNS, molesNS))
253    return _returnNotNoneText(creationDate)
254
255def findMolesPublishedDate(resourceXML):
256    creationDate = resourceXML.find('%sentity/%smolesISO/%spublished' % (molesNS, molesNS, molesNS))
257    return _returnNotNoneText(creationDate)
258
259def findMolesLineage(dataEntityMigration):
260    resourceXML = getAtomDocumentByMO(dataEntityMigration)
261    lineage = resourceXML.find('%sentity/%smolesISO/%slineage' % (molesNS, molesNS, molesNS))
262    if lineage is None:
263        raise NoDataLineage(dataEntityMigration)
264    return lineage.text
265
266def extractMolesProviderID(migrationObject):
267    resourceXML = getAtomDocumentByMO(migrationObject)
268    provider_id = resourceXML.find('%sentity/%smolesISO/%sproviderID' % (molesNS, molesNS, molesNS))
269    return _returnNotNoneText(provider_id)
270
271def extractMolesQuality(migrationObject):
272    resourceXML = getAtomDocumentByMO(migrationObject)
273    quality = resourceXML.find('%sentity/%smolesISO/%squality' % (molesNS, molesNS, molesNS))
274    return _returnNotNoneText(quality)
275
276def extractMolesTemporalRange(migrationObject):
277    resourceXML = getAtomDocumentByMO(migrationObject)
278    temporal_range = resourceXML.find('%stemporalRange' % (molesNS))
279    return _returnNotNoneText(temporal_range)
280
281def extractMolesCreationDate(migrationObject):
282    resourceXML = getAtomDocumentByMO(migrationObject)
283    return findMolesCreationDate(resourceXML)
284
285def extractMolesPublishedDate(migrationObject):
286    resourceXML = getAtomDocumentByMO(migrationObject)
287    return findMolesPublishedDate(resourceXML)
288
289def extractQuality(dataEntityMigration):
290    resourceXML = getAtomDocumentByMO(dataEntityMigration)
291    quality = resourceXML.find('%sentity/%smolesISO/%squality' % (molesNS, molesNS, molesNS))
292    return _returnNotNoneText(quality)
293
294def extractUpdateFrequency(dataEntityMigration):
295    resourceXML = getAtomDocumentByMO(dataEntityMigration)
296    update_frequency = resourceXML.find('%sentity/%smolesISO/%supdateFrequency' % (molesNS, molesNS, molesNS))
297    return _returnNotNoneText(update_frequency)
298
299def extractContent(dataEntityMigration):
300    """
301        Returns a dictionary containing the div composing the
302        <content> element in a dataentity document.
303    """
304    resourceXML = getAtomDocumentByMO(dataEntityMigration)
305    content = resourceXML.find('%scontent' % (atomNS))
306    text = _returnNotNoneText(content)
307    contentDict = {}
308    if text:
309        doc = htmlParser.parse(unescape(text))
310        for el in doc.findall('body//div'):   
311            prop = el.get('property')
312            if prop:
313                if prop.startswith('cedacat'):
314                    contentDict[prop.split(':')[1]] = escape(tostring(el))
315    return contentDict
316
317def _extractAuthors(authorsCSV):
318    if authorsCSV is None:
319        return []
320    authors = authorsCSV.split(',')
321    for index in range(len(authors)):
322        authors[index] = authors[index].strip()
323        if len(authors[index]) == 0:
324            authors.remove(authors[index])
325    return authors
326
327def findAuthorsInResource(resourceMigration):
328    '''
329        Returns a dictionary with the following keys:
330        'authors': a list of string representing the authors
331        'contributors': a list of string representing the contributors
332    '''
333    ret = {}   
334    resourceXML = getAtomDocumentByMO(resourceMigration)
335    ret['authors'] = findAuthorInResource(resourceXML)
336    ret['contributors'] = findContributorInResource(resourceXML)
337    return ret
338
339def findAuthorInResource(resourceXML): 
340    author = resourceXML.find('%sauthor/%sname' % (atomNS, atomNS))
341    return _returnNotNoneText(author)
342
343def findContributorInResource(resourceXML): 
344    contributors = resourceXML.find('%scontributor/%sname' % (atomNS, atomNS))
345    return _returnNotNoneText(contributors)
346
347def findPublishedDate(resourceMigration):
348    resourceXML = getAtomDocumentByMO(resourceMigration)
349    publishedDate = resourceXML.find('%spublished' % (atomNS))
350    return _returnNotNoneText(publishedDate)
351
352def findUpdatedDate(resourceMigration):
353    resourceXML = getAtomDocumentByMO(resourceMigration)
354    publishedDate = resourceXML.find('%supdated' % (atomNS))
355    return _returnNotNoneText(publishedDate)
356
357def findSummary(resourceMigration):
358    """
359        Returns the <entry><summary> tag of an atom document
360        @param resourceMigration: a MigrationObject instance
361        @return: the <summary> value or None if empty
362    """
363    resourceXML = getAtomDocumentByMO(resourceMigration)
364    summary = resourceXML.find('%ssummary' % (atomNS))
365    return _returnNotNoneText(summary)
366
367def findID(dataEntXML):
368    ent_id = dataEntXML.find('%sid' % (atomNS))
369    return _returnNotNoneText(ent_id)
370
371def _updateLinksDict(linksDict, link, linkMarker):
372    if not linksDict.has_key(linkMarker):
373        linksDict[linkMarker] = []
374    rel = link.get('rel')
375    if rel and rel.endswith('/' + linkMarker):
376        linksDict[linkMarker].append({'href': link.get('href'), 'title': link.get('title')}) 
377
378def _extractLinks(dataEntXML, markers):
379    linksDict = {}
380    links = dataEntXML.findall('%slink' % (atomNS))
381    for link in links:
382        for marker in markers:
383            _updateLinksDict(linksDict, link, marker)       
384    return linksDict
385
386def findLinksInMigrationDocument(dataEntityMigration):
387    dataEntXML = getAtomDocumentByMO(dataEntityMigration)
388    linksDict = _extractLinks(dataEntXML, linkMarkers)
389    return linksDict
390
391
392
393def findDownloadLinksInMigrationDocument(migrationObject):
394    """
395        Return a list of dictionaries describing a <link rel="...DOWNLOAD..."> tag type
396        Each dictionary has two keys: 'href' and 'title'
397        @param migrationObject: the migration instance to retrieve and parse
398        @return: a list of dictionaries
399    """
400    linksDict = findLinksInMigrationDocument(migrationObject)
401    if linksDict.has_key('DOWNLOAD'):
402        return linksDict['DOWNLOAD']   
403    return {}       
404
405def findAccessLinksInMigrationDocument(migrationObject):
406    """
407        Return a list of dictionaries describing a <link rel="...ACCESS..."> tag type
408        Each dictionary has two keys: 'href' and 'title'
409        @param migrationObject: the migration instance to retrieve and parse
410        @return: a list of dictionaries
411    """
412    linksDict = findLinksInMigrationDocument(migrationObject)
413    if linksDict.has_key('ACCESS'):
414        return linksDict['ACCESS']     
415    return {}   
416
417def findDocumentationInMigrationDocument(migrationObject):
418    """
419        Return a list of dictionaries describing a <link rel="...DOCUMENTATION..."> tag type
420        Each dictionary has two keys: 'href' and 'title'
421        @param migrationObject: the migration instance to retrieve and parse
422        @return: a list of dictionaries
423    """
424    linksDict = findLinksInMigrationDocument(migrationObject)
425    if linksDict.has_key('DOCUMENTATION'):
426        return linksDict['DOCUMENTATION']     
427    return {}
428
429def findDOIInMigrationDocument(migrationObject):
430    """
431        Return a dictionary describing a <link rel="...DOCUMENTATION..."> tag type
432        The dictionary has two keys: 'href' and 'title'
433        @param migrationObject: the migration instance to retrieve and parse
434        @return: a dictionary relative to the DOI, None otherwise
435    """
436    for link in findDocumentationInMigrationDocument(migrationObject):
437        if link['href'].startswith('http://dx.doi.org/doi:'):
438            return link
439    return None
440
441def findDeploymentsInDE(dataEntityMigration):
442    linksDict = findLinksInMigrationDocument(dataEntityMigration)
443    links = _extractLinksByMarker(linksDict, 'Deployment')
444    return [depName + '.atom' for depName in links]
445
446def findSubTypeInDPT(resourceMigration):
447    resourceXML = getAtomDocumentByMO(resourceMigration)
448    categories = resourceXML.findall('%scategory' % (atomNS))
449    for category in categories:
450        if category.get("term") == "ATOM_SUBTYPE":
451            return category.get("label")   
452       
453def extractTitle(deploymentMigration):
454    resourceXML = getAtomDocumentByMO(deploymentMigration)
455    title = resourceXML.find('%stitle' % (atomNS))
456    return _returnNotNoneText(title)
457
458def extractSummary(migrationObject):
459    resourceXML = getAtomDocumentByMO(migrationObject)
460    summary = resourceXML.find('%ssummary' % (atomNS))
461    return _returnNotNoneText(summary)
462
463def extractGeographicExtentInMigrationDocument(migrationObject):
464    """
465        Extracts if existing the georss:where/gel:Enveloper/upper-lowerCorner elements.
466        @param migrationObject: a migration object to retrieve to parse for data
467        @return: None if no data are found, otherwise a dictionary with keys: 'east', 'north', 'west', 'south' where
468        the values are float
469    """
470    resourceXML = getAtomDocumentByMO(migrationObject)
471    upperCorner = resourceXML.find('%swhere/%sEnvelope/%supperCorner' % (georssNS, gmlNS, gmlNS))
472    lowerCorner = resourceXML.find('%swhere/%sEnvelope/%slowerCorner' % (georssNS, gmlNS, gmlNS))
473    ret = None
474    if upperCorner != None and lowerCorner != None:
475        upperCornerData = upperCorner.text.split()
476        lowerCornerData = lowerCorner.text.split()
477        ret = {'east': float(upperCornerData[0]), 'north': float(upperCornerData[1]), 'west': float(lowerCornerData[0]), 'south': float(lowerCornerData[1])}
478    return ret
479
480def findLinksInDeployment(migrationObject):
481    """
482        Returns a dictionary of links owned by the given dataEntity document
483        @param deploymentMigration: a MigrationObject instance
484        @return: a dictionary of links.
485    """
486    links = {}
487    linksDict = findLinksInMigrationDocument(migrationObject)
488    for marker in linkMarkers:   
489        links[marker] = _extractLinksByMarker(linksDict, marker)
490    return links
491
492def _extractLinksByMarker(linksDict, marker):
493    dpt = []
494    if linksDict.has_key(marker):
495        for link in linksDict[marker]:
496            try:
497                linkLongName = link['href'].split('/')[-1]
498                if '__ATOM__' in linkLongName:
499                    linkName = linkLongName.rsplit('__ATOM__')[1]
500                else:
501                    linkName = linkLongName
502                dpt.append(linkName)
503            except Exception as ex:
504                print "WARN - Cannot extractLinksByMarker %s" % (link)
505    return dpt
506
507
508def getResourceRefs(deploymentRefs):
509    '''
510        Returns a list of Elements representing the inner resource reference items
511        @param resourceRefs: the name of the eXist collection name below the 'deployments' one
512    ''' 
513    XMLDepl = _getXMLDocument(deploymentRefs)
514    return XMLDepl.findall('%scollection/%sresource' % (existNS, existNS))
515
516def getOwnerRefs(docStatus, docType, docOwner):
517    '''
518        Returns a list of Elements representing the inner resource reference items
519        @param resourceRefs: the name of the eXist collection name below the 'deployments' one
520    '''     
521    XMLDepl = _getXMLDocument(buildExistOwnerPath(docStatus, docType, docOwner))
522    return XMLDepl.findall('%scollection/%sresource' % (existNS, existNS))
523
524def getTypeRefs(docStatus, docType):
525    '''
526        Returns a list of Elements representing the inner resource reference items
527        @param resourceRefs: the name of the eXist collection name below the 'deployments' one
528    '''     
529    XMLDepl = _getXMLDocument(buildExistTypePath(docStatus, docType))
530    return XMLDepl.findall('%scollection/%sresource' % (existNS, existNS))
531
532
533
534def getCollectionRefs(publishedRefs):
535    '''
536        Returns a list of Elements representing the inner deployment reference items
537        @param basePublished: the name of the eXist collection name below the 'published' one
538    ''' 
539    XMLPubl = _getXMLDocument(publishedRefs)
540    return XMLPubl.findall('%scollection/%scollection' % (existNS, existNS))
541
542def getResource(source, resourceName):
543    resourceSource = '%s/%s' % (source, resourceName)
544    resourceDoc = _getDocument(resourceSource)
545    return XML(resourceDoc)
546
547def createMD_Keywords(keywords, k_type=None, thesaurusName=None):
548    '''
549        Creates a new MD_Keywords instance.
550        @param keywords: a String array       
551    '''   
552    md_keywords = MD_Keywords()
553    md_keywords.keyword.extend(keywords)
554    if k_type:
555        md_keywords.type = k_type
556    if thesaurusName:
557        md_keywords.thesaurusName = thesaurusName       
558    return md_keywords
559   
560
561def createDateTime(datetime):
562    '''
563        Creates a new DateTime instance.
564        @param datetime: a datetime.datetime instance       
565    '''
566    dateTime = DateTime()
567    dateTime.century = (datetime.year / 100) + 1
568    dateTime.year = datetime.year
569    dateTime.month = datetime.month       
570    dateTime.day = datetime.day
571    dateTime.hour = datetime.hour
572    dateTime.minute = datetime.minute
573    dateTime.second = datetime.second
574    dateTime.timeZone = datetime.tzinfo       
575    return dateTime       
576       
577def createDate(date):
578    '''
579        Creates a new Date instance.
580        @param date: a datetime.datetime instance
581    '''
582    idate = Date()
583    idate.century = (date.year / 100) + 1
584    idate.year = date.year
585    idate.month = date.month       
586    idate.day = date.day       
587    return idate       
588       
589def createTM_Position(anyOther = None, date8601 = None, dateTime8601 = None, time8601 = None):
590    '''
591        Creates a new TM_Position instance
592        @param anyOther: a TM_TemporalPosition instance
593        @param date8601: a Date instance
594        @param dateTime8601:a DateTime instance
595        @param time8601: a Time instance   
596    '''
597    tm_position = TM_Position()
598    if anyOther:
599        tm_position.anyOther = anyOther
600    if date8601:
601        tm_position.date8601 = date8601 
602    if dateTime8601:
603        tm_position.dateTime8601 = dateTime8601
604    if time8601:
605        tm_position.time8601 = time8601
606    return tm_position           
607
608def createTM_Instant(position):
609    '''
610        Creates a new TM_Position instance
611        @param position: a TM_Position instance
612    '''
613    tm_instant = TM_Instant()
614    tm_instant.position = position
615    return tm_instant
616
617def createTM_Period(begin, end):
618    '''
619        Creates a new TM_Position instance
620        @param position: a TM_Position instance
621    '''
622    tm_period = TM_Period()
623    tm_period.begin = begin
624    tm_period.end = end   
625    return tm_period
626
627def createCI_Address(deliveryPoint = None, electronicMailAddress = None, city = None, country = None, postalCode = None):
628    '''
629        Creates a new CI_Address instance
630        @param deliveryPoint: an array of Strings
631        @param electronicMailAddress: an array of Strings
632        @param city: a string
633        @param country: a string               
634        @param postalCode: a string       
635    '''
636    ci_address = CI_Address()
637    if deliveryPoint:
638        ci_address.deliveryPoint = deliveryPoint
639    if electronicMailAddress:
640        ci_address.electronicMailAddress = electronicMailAddress       
641    if postalCode:
642        ci_address.postalCode = postalCode       
643    if city:
644        ci_address.city = city       
645    if country:
646        ci_address.country = country       
647    if postalCode:
648        ci_address.postalCode = postalCode       
649    return ci_address
650
651def createCI_OnlineResource(linkage, name=None):
652    '''
653        Creates a new CI_OnlineResource instance
654        @param linkage: a string (the URL class is associated with a String)
655        @param name: a String
656    '''
657    ci_online_resource = CI_OnlineResource()
658    ci_online_resource.linkage = linkage
659    if name:
660        ci_online_resource.name = name
661    return ci_online_resource
662
663def createCI_Telephone(voice=None, facsimile=None):
664    '''
665        Creates a new CI_Telephone instance
666        @param voice: an array of strings       
667        @param facsimile: an array of strings
668    '''
669    ci_telephone = CI_Telephone()
670    if voice:
671        ci_telephone.voice = voice
672    if facsimile:
673        ci_telephone.facsimile = voice       
674    return ci_telephone
675
676def createCI_Contact(phone, address = None, onlineResource = None):
677    '''
678        Creates a new CI_Contact instance
679        @param phone: a CI_Telephone instance       
680        @param address: a CI_Address instance
681        @param onlineResource: a CI_OnlineResource instance
682    '''
683    ci_contact = CI_Contact()
684    ci_contact.phone = phone
685    if address:
686        ci_contact.address = address
687    if onlineResource:
688        ci_contact.onlineResource = onlineResource       
689    return ci_contact
690
691def createMO_Individual(name = None, contactInfo = None):
692    '''
693        Creates a new MO_Individual instance
694        @param name: a String
695        @param contactInfo: an array of CI_Contact       
696    '''   
697    ci_party = MO_Individual()
698    if name:
699        ci_party.name = name
700    if contactInfo:
701        ci_party.contactInfo = contactInfo       
702    return ci_party
703
704def createMO_Organization(name = None, contactInfo = None):
705    '''
706        Creates a new MO_Organization instance.
707        @param name: a String
708        @param contactInfo: an array of CI_Contact       
709    '''       
710    ci_party = MO_Organisation()
711    if name:
712        ci_party.name = name
713    if contactInfo:
714        ci_party.contactInfo.extend(contactInfo)         
715    return ci_party
716
717def createMO_ResponsiblePartyInfo(role, i_party):
718    """
719        @param role: a CI_RoleCode/MO_RoleValue assigned to this ResponsibleParty
720        @param party: a list of MO_Organization/CI_Individual instances
721    """
722    mo_responsableInfo = MO_ResponsiblePartyInfo()
723    mo_responsableInfo.role = role
724    mo_responsableInfo.party.extend(i_party)
725    return mo_responsableInfo
726
727
728def createCI_Date(dateType, date = None):
729    """
730        Creates a new CI_Date
731        @param dateType: a CI_DateTypeCode value
732        @param date: a DateTime instance
733    """
734    ci_date = CI_Date()
735    ci_date.dateType = dateType
736    if date:
737        ci_date.date = date
738    return ci_date
739
740def createCI_Citation(title, date = None, icitedResponsibleParty = None):
741    """
742        Creates a new CI_Citation
743        @param title: the CI_Citation title
744        @param date: an array of CI_Date instances
745        @param icitedResponsibleParty: a list of CI_ResponsibleParty instances
746    """   
747    ci_citation = CI_Citation()
748    ci_citation.title = title
749    if date and type(date) == list:
750        ci_citation.date.extend(date)
751    if icitedResponsibleParty:
752        ci_citation.citedResponsibleParty.extend(icitedResponsibleParty)
753    return ci_citation
754
755def createMD_Constraints(useLimitation = None):
756    """
757        Creates a new MD_Constrains
758        @param useLimitation: a string array
759    """ 
760    md_constraints = MD_Constraints()
761    if useLimitation and type(useLimitation) == list:
762        md_constraints.useLimitation = useLimitation
763    return md_constraints
764
765def createMD_LegalConstraints(useLimitation = None, accessConstrains = None):
766    """
767        Creates a new MD_LegalConstrains
768        @param useLimitation: a string array
769        @param accessConstrains: an MD_RestrictionCode array
770    """ 
771    md_legalconstraints = MD_LegalConstraints()
772    if useLimitation and type(useLimitation) == list:
773        md_legalconstraints.useLimitation = useLimitation
774    if accessConstrains and type(accessConstrains) == list:
775        md_legalconstraints.accessConstrains = accessConstrains       
776    return md_legalconstraints
777
778def createMD_Identifier(code, authority = None):
779    """
780        Creates a new MD_Identifier
781        @param code: a String
782        @param authority: a CI_Citation instance
783    """
784    md_identifier = MD_Identifier()
785    if code == None:
786        raise NoNullableElement()
787    md_identifier.code = code
788    if authority:
789        md_identifier.authority = authority
790    return md_identifier
791
792def createCI_ResponsibleParty(role, organizationName = None, individualName = None):
793    """
794        Creates a new CI_ResponsibeParty
795        @param role: a CI_RoleCode
796    """
797    ci_responsible_party = CI_ResponsibleParty()
798    ci_responsible_party.role = role
799    if organizationName:
800        ci_responsible_party.organisationName = organizationName
801    if individualName:
802        ci_responsible_party.individualName = individualName   
803    return ci_responsible_party
804
805def createMD_Metadata(date_stamp, contact, language = None):
806    """
807        Creates a new MD_Metadata
808        @param date_stamp: a Date instance
809        @param contacts: a CI_ResponsibleParty array instances
810        @param language: a string
811    """   
812    md_metadata = MD_Metadata()
813    md_metadata.dateStamp = date_stamp
814    for item in contact:
815        md_metadata.contact.append(item)
816    if language:
817        md_metadata.language = language   
818    return md_metadata
819
820def createMO_OnlineResource(linkage, instance = None, name = None, function = None, description = None, applicationProfile = None):
821    """
822        Creates a new CEDA_Result
823        @param linkage: the MO_OnlineResource.linkage.url.??? field
824        @param name: the MO_OnlineResource.linkage.name field
825        @param function: the MO_OnlineResource.function field
826        @param description: the MO_OnlineResource.description field
827        @param applicationProfile: the MO_OnlineResource.applicationProfile field
828    """
829    if instance is None:
830        on_line_resource = MO_OnlineResource()
831         
832    on_line_resource.linkage = linkage
833    if name and on_line_resource.name != name:         
834        on_line_resource.name = name
835    if function and on_line_resource.function != function:
836        on_line_resource.function = function
837    if description and on_line_resource.description != description:
838        on_line_resource.description = description
839    if applicationProfile and on_line_resource.applicationProfile != applicationProfile:
840        on_line_resource.applicationProfile = applicationProfile
841    return on_line_resource       
842
843def createCEDA_Result(curation_category, internal_path, source = None):
844    """
845        Creates a new CEDA_Result
846        @param curation_category: a CEDA_CurationValue instance
847        @param internal_path: a String
848        @param source: an array of MO_OnlineResource instances
849    """
850    ceda_result = CEDA_Result()
851    ceda_result.curationCategory = curation_category
852    ceda_result.internalPath = internal_path           
853    if source: 
854        ceda_result.source = source
855    return ceda_result
856
857
858
859def createDQ_ConformanceResult(explanation, pass_, specification):
860    """
861        Creates a DQ_ConformanceResult instance
862        @param explanation: a String
863        @param pass_: a boolean value
864        @param specification: a CI_Citation instance 
865    """
866    dq_conformanceResult = DQ_ConformanceResult()
867    dq_conformanceResult.explanation = explanation
868    dq_conformanceResult.pass_ = pass_
869    dq_conformanceResult.specification = specification
870    return dq_conformanceResult
871
872def createDQ_Element(result):
873    """
874        Creates a DQ_Element instance
875        @param result: a DQ_Result array (mix 1, max 2 items)
876    """
877    dq_element = DQ_Element()
878    if result and (type(result) == list) and (len(result) >= 1 and len(result) <= 2):
879        dq_element.result = result
880    return dq_element
881
882def createEX_GeographicBoundingBox(east, north, west, south):
883    """
884        Creates an EX_GeographicBoundingBox instance
885        @param east: the eastBoundLongitude attribute as float
886        @param north: the northBoundLongitude attribute as float
887        @param west: the westBoundLongitude attribute as float
888        @param south: the southBoundLongitude attribute as float               
889    """
890    ex_geographic_bb = EX_GeographicBoundingBox()
891    ex_geographic_bb.eastBoundLongitude = east
892    ex_geographic_bb.northBoundLatitude = north
893    ex_geographic_bb.westBoundLongitude = west
894    ex_geographic_bb.southBoundLatitude = south
895    return ex_geographic_bb
896   
897def createCEDA_Processing():
898    ceda_processing = CEDA_Processing()
899    return ceda_processing
900
901
902def createCEDA_Instrument():
903    ceda_instrument = CEDA_Instrument()
904    return ceda_instrument
905
906def createCEDA_CompositeProcess():
907    ceda_cp = CEDA_CompositeProcess()
908    return ceda_cp
909
910def createCEDA_Acquisition():
911    ceda_acquisition = CEDA_Acquisition()
912    return ceda_acquisition
913
914def createCEDA_Review(reviewer, reviewFrequency, reviewStatus):
915    """
916        Returns a new CEDA_Review
917        @param reviewer: an MO_ResponsibilityPartyInfo
918        @param reviewFrequency: a CEDA_ReviewFrequencyValue
919        @param reviewStatus: a CEDA_ReviewStatusValue
920    """
921    ceda_review = CEDA_Review()
922    ceda_review.reviewer = reviewer
923    ceda_review.reviewFrequency = reviewFrequency
924    ceda_review.reviewStatus = reviewStatus           
925    return ceda_review
926
927def createCEDA_Project(abstract = None, publication_state = None, documentation = None, project_resource=None):
928    ceda_project = CEDA_Project()
929    if abstract:
930        ceda_project.abstract = abstract
931    if publication_state:
932        ceda_project.publicationState = publication_state       
933    if documentation and type(documentation) == list:
934        ceda_project.documentation = documentation
935    if project_resource and type(project_resource) == list:
936        ceda_project.projectResource = project_resource   
937    return ceda_project
938
939def fromDateStringToPhenomenonTime(doc_phenomenon_time):
940    """
941        Transforms a date string like '2002-07-22' (startDate) in a TM_Instant instance or   
942        '2002-07-22/2011-08-06' (start/endDate) in a TM_Period instance
943        @param doc_phenomenon_time: a date string in the expected format
944    """
945    if doc_phenomenon_time:
946        pt = None
947        if '/' in doc_phenomenon_time:
948            period = doc_phenomenon_time.split('/')
949            begin_date = createDate(isoDateStringToTimeDate(period[0]))
950            begin_position = createTM_Position(date8601 = begin_date)
951            begin_tm_instant = createTM_Instant(begin_position)
952           
953            end_date = createDate(isoDateStringToTimeDate(period[1]))
954            end_position = createTM_Position(date8601 = end_date)
955            end_tm_instant = createTM_Instant(end_position)
956           
957            pt = createTM_Period(begin_tm_instant, end_tm_instant)
958        else:
959            tm_position = createTM_Position(date8601 = createDate(isoDateStringToTimeDate(doc_phenomenon_time)))
960            pt = createTM_Instant(tm_position)
961    return pt
962
963def fromPhenomenonTimeToString(phenomenonTime):
964    """
965        Transforms a TM_Instant instance in a date string like '2002-07-22' (startDate) or   
966        a TM_Period instance in a string like '2002-07-22/2011-08-06' (start/endDate)
967        @param phenomenonTime: a aTM_Instace or a TM_Period instance
968        @return a pair startDate, endDate. If endDate does not exists return startDate, None
969    """   
970    if phenomenonTime is None:
971        return None
972    startDate =None
973    endDate = None
974    if isinstance(phenomenonTime, TM_Instant):
975        startDate = _tm_InstantToString(phenomenonTime)
976    elif isinstance(phenomenonTime, TM_Period):
977        startDate = _tm_InstantToString(phenomenonTime.begin)       
978        endDate = _tm_InstantToString(phenomenonTime.end)
979    return startDate, endDate
980
981def comparePhenomenonTimes(p1, p2):
982    s1 = fromPhenomenonTimeToString(p1)
983    s2 = fromPhenomenonTimeToString(p2)
984    return s1[0] == s2[0] and s1[1] == s2[1] 
985
986def _tm_InstantToString(tm_instant):
987    idate = tm_instant.position.date8601
988    return str(datetime.date(int(idate.year), int(idate.month), int(idate.day)))
989
990def fromGeographicBoundingBoxToString(geographicBoundingBox):
991    if geographicBoundingBox is None:
992        return None
993    return ('%f %f,%f %f') % (geographicBoundingBox.eastBoundLongitude, geographicBoundingBox.northBoundLatitude, \
994                              geographicBoundingBox.westBoundLongitude, geographicBoundingBox.southBoundLatitude)
995   
996def compareGeographicBoundingBoxes(gb1, gb2):
997    return fromGeographicBoundingBoxToString(gb1) == fromGeographicBoundingBoxToString(gb2)
Note: See TracBrowser for help on using the repository browser.