source: mauRepo/MolesManager/trunk/cedaMoles/libs/migration/processor/commons.py @ 8517

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

Incomplete - # 22534: Add versiojn number to the gui page
 http://team.ceda.ac.uk/trac/ceda/ticket/22534
New classes for the moles2gui library

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 cedaMoles.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.ceda_metadatamodel.ceda_project.ceda_project import CEDA_Project
43from ea_model.ceda_metadatamodel.ceda_utilities.ceda_review import CEDA_Review   
44from ea_model.ceda_metadatamodel.ceda_acquisition.ceda_instrument import CEDA_Instrument
45from ea_model.ceda_metadatamodel.ceda_computation.ceda_processing import CEDA_Processing
46from ea_model.ceda_metadatamodel.ceda_result.ceda_result import CEDA_Result
47from ea_model.moles3_4.utilities.mo_individual import MO_Individual
48from ea_model.moles3_4.utilities.mo_organisation import MO_Organisation
49from ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_instant import TM_Instant
50from ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_period import TM_Period
51from ea_model.moles3_4.result.mo_onlineresource import MO_OnlineResource
52from ea_model.ceda_metadatamodel.ceda_acquisition.ceda_acquisition import CEDA_Acquisition
53
54from ea_model.iso_19103_2005_schema_language.basic_types.\
55    primitive.date_and_time.datetime import DateTime
56from ea_model.iso_19103_2005_schema_language.basic_types.\
57    primitive.date_and_time.date import Date
58from ea_model.iso_19108_2006_temporal_schema.temporal_reference_system.\
59    tm_position import TM_Position
60   
61from ea_model.iso_19115_2006_metadata_corrigendum.\
62    reference_system_information.md_identifier import MD_Identifier
63from ea_model.iso_19115_2006_metadata_corrigendum.\
64    identification_information.md_keywords import MD_Keywords   
65from ea_model.iso_19115_2006_metadata_corrigendum.\
66    citation_and_responsible_party_information.ci_address import CI_Address
67from ea_model.iso_19115_2006_metadata_corrigendum.\
68    citation_and_responsible_party_information.ci_onlineresource import CI_OnlineResource
69from ea_model.iso_19115_2006_metadata_corrigendum.\
70    citation_and_responsible_party_information.ci_telephone import CI_Telephone
71from ea_model.iso_19115_2006_metadata_corrigendum.\
72    citation_and_responsible_party_information.ci_contact import CI_Contact
73from ea_model.iso_19115_2006_metadata_corrigendum.\
74    citation_and_responsible_party_information.ci_date import CI_Date
75from ea_model.iso_19115_2006_metadata_corrigendum.\
76    citation_and_responsible_party_information.ci_citation import CI_Citation
77from ea_model.iso_19115_2006_metadata_corrigendum.\
78    constraint_information.md_constraints import MD_Constraints
79from ea_model.iso_19115_2006_metadata_corrigendum.\
80    constraint_information.md_legalconstraints import MD_LegalConstraints
81from ea_model.iso_19115_2006_metadata_corrigendum.\
82    citation_and_responsible_party_information.ci_responsibleparty \
83        import CI_ResponsibleParty
84from ea_model.iso_19115_2006_metadata_corrigendum.\
85    metadata_entity_set_information.md_metadata import MD_Metadata
86from ea_model.iso_19115_2006_metadata_corrigendum.\
87    data_quality_information.dq_conformanceresult import DQ_ConformanceResult
88from ea_model.iso_19115_2006_metadata_corrigendum.\
89    extent_information.ex_geographicboundingbox import EX_GeographicBoundingBox
90from ea_model.iso_19115_2006_metadata_corrigendum.\
91    data_quality_information.dq_element import DQ_Element
92   
93from ea_model.ceda_metadatamodel.ceda_observationprocess.\
94    ceda_compositeprocess import CEDA_CompositeProcess
95
96base = '/exist/rest/atoms'
97
98DS_pUBLISHED = 'published'
99DS_WORKING = 'working'
100DS_PUBLISHED = 'Published'
101DOC_STATUS = (DS_pUBLISHED, DS_WORKING, DS_PUBLISHED)
102
103DT_DEPLOYMENTS = 'deployments'
104DT_DATA_ENTITIES = 'data_entities'
105DT_DEPLOYMENT_DATA = 'deployment_data'
106DT_DATA_GRANULES = 'data_granules'
107DOC_TYPES = (DT_DEPLOYMENTS, DT_DATA_ENTITIES, DT_DEPLOYMENT_DATA, DT_DATA_GRANULES)
108
109DO_BADC = 'badc.nerc.ac.uk'
110DO_NEODC = 'neodc.nerc.ac.uk'
111DO_UKSSDC = 'ukssdc.ac.uk'
112
113CEDA = 'Centre for Environmental Data Archive'
114DOC_OWNERS = (DO_BADC, DO_NEODC, DO_UKSSDC)
115
116ATOM_NS = "{http://www.w3.org/2005/Atom}"
117EXIST_NS = "{http://exist.sourceforge.net/NS/exist}"
118MOLES_NS = "{http://ndg.nerc.ac.uk/schema/moles2beta}"
119#htmlNS = "{http://www.w3.org/1999/xhtml}"
120GEORSS_NS = "{http://www.georss.org/georss/10}"
121GML_NS = "{http://www.opengis.net/gml}"
122DATE_FORMAT = '%Y-%m-%d'
123DATETIME_FORMAT = DATE_FORMAT + 'T%H:%M:%SZ'
124HOST = 'bora.badc.rl.ac.uk'
125PORT = '8080'
126
127LINK_MARKERS = ['Deployment', 'DOWNLOAD', 'DOCUMENTATION', 'ACCESS', 'LOGO', 'ACTIVITY', \
128               'DPT', 'OBS']
129
130#MD_Identifier codes
131MD_CODE_MOLES2_CITATION = 'ceda_moles2_citation'
132
133HTML_PARSER = html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("etree"), \
134                                 namespaceHTMLElements=False)
135
136def calculate_hash(text):
137    """
138        Returns an md5 hexadecimal representation of the given text
139        @param text: the string to encode
140        @return: the hexadecimal md5 value of the given text
141    """
142    encoder = md5()
143    encoder.update(text)
144    return encoder.hexdigest()
145
146def build_exist_doc_path(doc_status, doc_type, doc_owner, doc_name):
147    '''
148        @param doc_status: one value from commons.docStatus
149        @param doc_type: one value from commons.docTypes
150        @param doc_owner: one value from commons.DOC_OWNERS
151        @param doc_name: one value from commons.DOC_OWNERS       
152    '''       
153    return '%s/%s' % (_build_exist_owner_path(doc_status, doc_type, doc_owner), doc_name)
154
155def _build_exist_owner_path(doc_status, doc_type, doc_owner):
156    '''
157        @param doc_status: one value from commons.docStatus
158        @param doc_type: one value from commons.docCollections
159        @param doc_owner: one value from commons.DOC_OWNERS
160    '''       
161    return '%s/%s' % (build_exist_type_path(doc_status, doc_type), doc_owner)
162
163def build_exist_type_path(doc_status, doc_type):
164    '''
165        @param doc_status: one value from commons.docStatus
166        @param doc_type: one value from commons.docCollections
167    '''       
168    return '%s/%s' % ('/exist/rest/atoms/%s' % (doc_status), doc_type)
169
170def _get_atom_document_by_mo(migration_object):
171    if migration_object is None:
172        raise Exception("migrationObject is None")
173    mo_type_dict = {'DeploymentsMigration': DT_DEPLOYMENTS, \
174                   'DataEntityMigration': DT_DATA_ENTITIES, \
175                   'DeploymentDataMigration': DT_DEPLOYMENT_DATA}     
176    return get_atom_document_as_elementtree(migration_object.doc_status, \
177                                    mo_type_dict[type(migration_object).__name__], \
178                                    migration_object.doc_owner, migration_object.doc_name)
179
180def get_atom_document_hash_by_mo(migration_object):
181    if migration_object is None:
182        raise Exception("migrationObject is None")   
183    mo_type_dict = {'DeploymentsMigration': DT_DEPLOYMENTS, \
184                   'DataEntityMigration': DT_DATA_ENTITIES, \
185                   'DeploymentDataMigration': DT_DEPLOYMENT_DATA}     
186    text = _get_atom_document_as_text(migration_object.doc_status, \
187                                  mo_type_dict[type(migration_object).__name__],\
188                                   migration_object.doc_owner, migration_object.doc_name)
189    return calculate_hash(text)
190
191def has_mo_been_processed(migration_object):
192    '''
193        Checks if a migration object has been already processed.
194        @param migrationObject: an instance of DataEntityMigration or DeploymentsMigration
195        @return True if has been processed, otherwise False
196    '''
197    if migration_object is None:
198        return False
199   
200    if not hasattr(migration_object, 'doc_hash'):
201        return False
202    else:
203        if migration_object.doc_hash is None:
204            return False
205       
206    return True
207
208def has_mo_same_hash(migration_object):
209    '''
210        Checks if a migration object has changed.
211        @param migrationObject: an instance of DataEntityMigration or
212            DeploymentsMigration or DeploymentDataMigration
213        @return True if the hash of the actual document is the
214            same of the migrationObject, otherwise False
215    '''
216    if not has_mo_been_processed(migration_object):
217        return False
218    return get_atom_document_hash_by_mo(migration_object) == migration_object.doc_hash
219
220def _get_atom_document_as_text(doc_status, doc_type, doc_owner, doc_name):
221    source = build_exist_doc_path(doc_status, doc_type, doc_owner, doc_name)
222    return _get_document(source)
223
224def get_atom_document_as_elementtree(doc_status, doc_type, doc_owner, doc_name):
225    source = build_exist_doc_path(doc_status, doc_type, doc_owner, doc_name)
226    return _get_xml_document(source)
227
228def _get_xml_document(source):
229    return XML(_get_document(source))
230
231def stringToTimestamp(timestring):
232    '''
233        Return a timestamp such as is returned by time.time().
234        @param timestring: a time string formatted as '%Y-%m-%dT%H:%M:%SZ'
235    '''   
236    return datetime.datetime.fromtimestamp(\
237                                time.mktime(time.strptime(timestring, DATETIME_FORMAT)))
238
239def isoDateStringToTimeDate(datestring):
240    '''
241        Return a datatime.datatime instance.
242        @param datestring: a date string formatted as '%Y-%m-%d'
243    '''
244    return datetime.datetime.strptime(datestring, DATE_FORMAT)
245
246def isoDateTimeStringToTimeDate(timestring):
247    '''
248        Return a datatime.datatime instance.
249        @param timestring: a time string formatted as '%Y-%m-%dT%H:%M:%SZ'
250    '''
251    try:
252        return datetime.datetime.strptime(timestring, DATETIME_FORMAT)
253    except:
254        pass
255
256def _get_document(source):
257    conn = HTTPConnection(host = HOST, port = PORT)
258    conn.connect()
259    conn.request('GET', source)
260    res = conn.getresponse()
261    xml_doc = res.read()
262    conn.close()
263    return xml_doc
264
265def _return_not_none_text(element):
266    if element is None:
267        return None
268    return element.text
269
270def find_moles_creation_date(resource_xml):
271    creation_date = resource_xml.find('%sentity/%smolesISO/%screated' \
272                                    % (MOLES_NS, MOLES_NS, MOLES_NS))
273    return _return_not_none_text(creation_date)
274
275def _find_moles_published_date(resource_xml):
276    creation_date = resource_xml.find('%sentity/%smolesISO/%spublished' \
277                                    % (MOLES_NS, MOLES_NS, MOLES_NS))
278    return _return_not_none_text(creation_date)
279
280def find_moles_lineage(data_entity_migration):
281    resource_xml = _get_atom_document_by_mo(data_entity_migration)
282    lineage = resource_xml.find('%sentity/%smolesISO/%slineage' \
283                               % (MOLES_NS, MOLES_NS, MOLES_NS))
284    if lineage is None:
285        raise NoDataLineage(data_entity_migration)
286    return lineage.text
287
288def extract_moles_provider_id(migration_object):
289    resource_xml = _get_atom_document_by_mo(migration_object)
290    provider_id = resource_xml.find('%sentity/%smolesISO/%sproviderID' \
291                                   % (MOLES_NS, MOLES_NS, MOLES_NS))
292    return _return_not_none_text(provider_id)
293
294def extract_moles_temporal_range(migration_object):
295    resource_xml = _get_atom_document_by_mo(migration_object)
296    temporal_range = resource_xml.find('%stemporalRange' % (MOLES_NS))
297    return _return_not_none_text(temporal_range)
298
299def extract_moles_creation_date(migration_object):
300    resource_xml = _get_atom_document_by_mo(migration_object)
301    return find_moles_creation_date(resource_xml)
302
303def extract_moles_published_date(migration_object):
304    resource_xml = _get_atom_document_by_mo(migration_object)
305    return _find_moles_published_date(resource_xml)
306
307def extract_quality(data_entity_migration):
308    resource_xml = _get_atom_document_by_mo(data_entity_migration)
309    quality = resource_xml.find('%sentity/%smolesISO/%squality' \
310                               % (MOLES_NS, MOLES_NS, MOLES_NS))
311    return _return_not_none_text(quality)
312
313def extract_update_frequency(data_entity_migration):
314    resource_xml = _get_atom_document_by_mo(data_entity_migration)
315    update_frequency = resource_xml.find('%sentity/%smolesISO/%supdateFrequency' \
316                                        % (MOLES_NS, MOLES_NS, MOLES_NS))
317    return _return_not_none_text(update_frequency)
318
319def extract_content(data_entity_migration):
320    """
321        Returns a dictionary containing the div composing the
322        <content> element in a dataentity document.
323    """
324    resource_xml = _get_atom_document_by_mo(data_entity_migration)
325    content = resource_xml.find('%scontent' % (ATOM_NS))
326    text = _return_not_none_text(content)
327    contentDict = {}
328    if text:
329        doc = HTML_PARSER.parse(unescape(text))
330        for el in doc.findall('body//div'):   
331            prop = el.get('property')
332            if prop:
333                if prop.startswith('cedacat'):
334                    contentDict[prop.split(':')[1]] = escape(tostring(el))
335    return contentDict
336
337def find_authors_in_resource(resource_migration):
338    '''
339        Returns a dictionary with the following keys:
340        'authors': a list of string representing the authors
341        'contributors': a list of string representing the contributors
342    '''
343    ret = {}   
344    resource_xml = _get_atom_document_by_mo(resource_migration)
345    ret['authors'] = _find_author_in_resource(resource_xml)
346    ret['contributors'] = _find_contributor_in_resource(resource_xml)
347    return ret
348
349def _find_author_in_resource(resource_xml): 
350    author = resource_xml.find('%sauthor/%sname' % (ATOM_NS, ATOM_NS))
351    return _return_not_none_text(author)
352
353def _find_contributor_in_resource(resource_xml): 
354    contributors = resource_xml.find('%scontributor/%sname' % (ATOM_NS, ATOM_NS))
355    return _return_not_none_text(contributors)
356
357def find_published_date(resource_migration):
358    resource_xml = _get_atom_document_by_mo(resource_migration)
359    publishedDate = resource_xml.find('%spublished' % (ATOM_NS))
360    return _return_not_none_text(publishedDate)
361
362def find_updated_date(resource_migration):
363    resource_xml = _get_atom_document_by_mo(resource_migration)
364    publishedDate = resource_xml.find('%supdated' % (ATOM_NS))
365    return _return_not_none_text(publishedDate)
366
367def find_summary(resource_migration):
368    """
369        Returns the <entry><summary> tag of an atom document
370        @param resourceMigration: a MigrationObject instance
371        @return: the <summary> value or None if empty
372    """
373    resource_xml = _get_atom_document_by_mo(resource_migration)
374    summary = resource_xml.find('%ssummary' % (ATOM_NS))
375    return _return_not_none_text(summary)
376
377def find_id(data_ent_xml):
378    ent_id = data_ent_xml.find('%sid' % (ATOM_NS))
379    return _return_not_none_text(ent_id)
380
381def _update_links_dict(links_dict, link, link_marker):
382    if not links_dict.has_key(link_marker):
383        links_dict[link_marker] = []
384    rel = link.get('rel')
385    if rel and rel.endswith('/' + link_marker):
386        links_dict[link_marker].append({'href': link.get('href'), \
387                                      'title': link.get('title')}) 
388
389def _extract_links(data_ent_xml, markers):
390    links_dict = {}
391    links = data_ent_xml.findall('%slink' % (ATOM_NS))
392    for link in links:
393        for marker in markers:
394            _update_links_dict(links_dict, link, marker)       
395    return links_dict
396
397def find_links_in_migration_document(data_entity_migration):
398    data_ent_XML = _get_atom_document_by_mo(data_entity_migration)
399    links_dict = _extract_links(data_ent_XML, LINK_MARKERS)
400    return links_dict
401
402
403
404def find_download_links_in_migration_document(migration_object):
405    """
406        Return a list of dictionaries describing a <link rel="...DOWNLOAD..."> tag type
407        Each dictionary has two keys: 'href' and 'title'
408        @param migrationObject: the migration instance to retrieve and parse
409        @return: a list of dictionaries
410    """
411    links_dict = find_links_in_migration_document(migration_object)
412    if links_dict.has_key('DOWNLOAD'):
413        return links_dict['DOWNLOAD']   
414    return {}       
415
416def find_access_links_in_migration_document(migration_object):
417    """
418        Return a list of dictionaries describing a <link rel="...ACCESS..."> tag type
419        Each dictionary has two keys: 'href' and 'title'
420        @param migrationObject: the migration instance to retrieve and parse
421        @return: a list of dictionaries
422    """
423    links_dict = find_links_in_migration_document(migration_object)
424    if links_dict.has_key('ACCESS'):
425        return links_dict['ACCESS']     
426    return {}   
427
428def find_documentation_in_migration_document(migration_object):
429    """
430        Return a list of dictionaries describing a <link rel="...DOCUMENTATION...">
431        tag type
432        Each dictionary has two keys: 'href' and 'title'
433        @param migrationObject: the migration instance to retrieve and parse
434        @return: a list of dictionaries
435    """
436    links_dict = find_links_in_migration_document(migration_object)
437    if links_dict.has_key('DOCUMENTATION'):
438        return links_dict['DOCUMENTATION']     
439    return {}
440
441def find_doi_in_migration_document(migration_object):
442    """
443        Return a dictionary describing a <link rel="...DOCUMENTATION..."> tag type
444        The dictionary has two keys: 'href' and 'title'
445        @param migrationObject: the migration instance to retrieve and parse
446        @return: a dictionary relative to the DOI, None otherwise
447    """
448    for link in find_documentation_in_migration_document(migration_object):
449        if link['href'].startswith('http://dx.doi.org/doi:'):
450            return link
451    return None
452
453def find_deployments_in_de(data_entity_migration):
454    links_dict = find_links_in_migration_document(data_entity_migration)
455    links = _extract_links_by_marker(links_dict, 'Deployment')
456    return [depName + '.atom' for depName in links]
457
458def find_subtype_in_dpt(resourceMigration):
459    resource_xml = _get_atom_document_by_mo(resourceMigration)
460    categories = resource_xml.findall('%scategory' % (ATOM_NS))
461    for category in categories:
462        if category.get("term") == "ATOM_SUBTYPE":
463            return category.get("label")   
464       
465def extract_title(deploymentMigration):
466    resource_xml = _get_atom_document_by_mo(deploymentMigration)
467    title = resource_xml.find('%stitle' % (ATOM_NS))
468    return _return_not_none_text(title)
469
470def extract_summary(migrationObject):
471    resource_xml = _get_atom_document_by_mo(migrationObject)
472    summary = resource_xml.find('%ssummary' % (ATOM_NS))
473    return _return_not_none_text(summary)
474
475def extract_ge_in_migration_doc(migration_object):
476    """
477        Extracts if existing the georss:where/gel:Enveloper/upper-lowerCorner elements.
478        @param migrationObject: a migration object to retrieve to parse for data
479        @return: None if no data are found, otherwise a dictionary with keys: 'east',
480        'north', 'west', 'south' where
481        the values are float
482    """
483    resource_xml = _get_atom_document_by_mo(migration_object)
484    upper_corner = resource_xml.find('%swhere/%sEnvelope/%supperCorner' \
485                                   % (GEORSS_NS, GML_NS, GML_NS))
486    lower_corner = resource_xml.find('%swhere/%sEnvelope/%slowerCorner' \
487                                   % (GEORSS_NS, GML_NS, GML_NS))
488    ret = None
489    if upper_corner != None and lower_corner != None:
490        upper_corner_data = upper_corner.text.split()
491        lower_corner_data = lower_corner.text.split()
492        ret = {'east': float(upper_corner_data[0]), 'north': float(upper_corner_data[1]), \
493               'west': float(lower_corner_data[0]), 'south': float(lower_corner_data[1])}
494    return ret
495
496def find_links_in_deployment(migration_object):
497    """
498        Returns a dictionary of links owned by the given dataEntity document
499        @param deploymentMigration: a MigrationObject instance
500        @return: a dictionary of links.
501    """
502    links = {}
503    links_dict = find_links_in_migration_document(migration_object)
504    for marker in LINK_MARKERS:   
505        links[marker] = _extract_links_by_marker(links_dict, marker)
506    return links
507
508def _extract_links_by_marker(links_dict, marker):
509    dpt = []
510    if links_dict.has_key(marker):
511        for link in links_dict[marker]:
512            try:
513                linkLongName = link['href'].split('/')[-1]
514                if '__ATOM__' in linkLongName:
515                    linkName = linkLongName.rsplit('__ATOM__')[1]
516                else:
517                    linkName = linkLongName
518                dpt.append(linkName)
519            except Exception as ex:
520                print "WARN - Cannot extractLinksByMarker %s" % (link)
521    return dpt
522
523def get_owner_refs(doc_status, doc_type, doc_owner):
524    '''
525        Returns a list of Elements representing the inner resource reference items
526        @param resourceRefs: the name of the eXist collection name below the
527        'deployments' one
528    '''     
529    xml_depl = _get_xml_document(_build_exist_owner_path(doc_status, doc_type, doc_owner))
530    return xml_depl.findall('%scollection/%sresource' % (EXIST_NS, EXIST_NS))
531
532def get_collection_refs(published_refs):
533    '''
534        Returns a list of Elements representing the inner deployment reference items
535        @param basePublished: the name of the eXist collection name below the
536        'published' one
537    ''' 
538    xml_publ = _get_xml_document(published_refs)
539    return xml_publ.findall('%scollection/%scollection' % (EXIST_NS, EXIST_NS))
540
541def create_md_keywords(keywords, k_type=None, thesaurusName=None):
542    '''
543        Creates a new MD_Keywords instance.
544        @param keywords: a String array       
545    '''   
546    md_keywords = MD_Keywords()
547    md_keywords.keyword.extend(keywords)
548    if k_type:
549        md_keywords.type = k_type
550    if thesaurusName:
551        md_keywords.thesaurusName = thesaurusName       
552    return md_keywords
553   
554
555def create_datetime(datetime):
556    '''
557        Creates a new DateTime instance.
558        @param datetime: a datetime.datetime instance       
559    '''
560    if datetime is None:
561        return
562    dateTime = DateTime()
563    dateTime.century = (datetime.year / 100) + 1
564    dateTime.year = datetime.year
565    dateTime.month = datetime.month       
566    dateTime.day = datetime.day
567    dateTime.hour = datetime.hour
568    dateTime.minute = datetime.minute
569    dateTime.second = datetime.second
570    dateTime.timeZone = datetime.tzinfo       
571    return dateTime       
572       
573def create_date(date):
574    '''
575        Creates a new Date instance.
576        @param date: a datetime.datetime instance
577    '''
578    idate = Date()
579    idate.century = (date.year / 100) + 1
580    idate.year = date.year
581    idate.month = date.month       
582    idate.day = date.day       
583    return idate       
584       
585def create_tm_position(anyOther = None, \
586                      date8601 = None, \
587                      dateTime8601 = None, \
588                      time8601 = None):
589    '''
590        Creates a new TM_Position instance
591        @param anyOther: a TM_TemporalPosition instance
592        @param date8601: a Date instance
593        @param dateTime8601:a DateTime instance
594        @param time8601: a Time instance   
595    '''
596    tm_position = TM_Position()
597    if anyOther:
598        tm_position.anyOther = anyOther
599    if date8601:
600        tm_position.date8601 = date8601 
601    if dateTime8601:
602        tm_position.dateTime8601 = dateTime8601
603    if time8601:
604        tm_position.time8601 = time8601
605    return tm_position           
606
607def create_tm_instant(position):
608    '''
609        Creates a new TM_Position instance
610        @param position: a TM_Position instance
611    '''
612    tm_instant = TM_Instant()
613    tm_instant.position = position
614    return tm_instant
615
616def create_tm_period(begin, end):
617    '''
618        Creates a new TM_Position instance
619        @param position: a TM_Position instance
620    '''
621    tm_period = TM_Period()
622    tm_period.begin = begin
623    tm_period.end = end   
624    return tm_period
625
626def create_ci_address(deliveryPoint = None, electronicMailAddress = None, \
627                     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 create_ci_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 create_ci_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 create_ci_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 create_mo_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 create_mo_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 create_mo_responsible_party_info(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 create_ci_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 create_ci_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 is not None:
750        if isinstance(date, list):
751            ci_citation.date.extend(date)
752        else:
753            ci_citation.date.append(date)
754    if icitedResponsibleParty:
755        ci_citation.citedResponsibleParty.extend(icitedResponsibleParty)
756    return ci_citation
757
758def create_md_constraints(useLimitation = None):
759    """
760        Creates a new MD_Constrains
761        @param useLimitation: a string array
762    """ 
763    md_constraints = MD_Constraints()
764    if useLimitation and type(useLimitation) == list:
765        md_constraints.useLimitation = useLimitation
766    return md_constraints
767
768def create_md_legal_constraints(useLimitation = None, accessConstrains = None):
769    """
770        Creates a new MD_LegalConstrains
771        @param useLimitation: a string array
772        @param accessConstrains: an MD_RestrictionCode array
773    """ 
774    md_legalconstraints = MD_LegalConstraints()
775    if useLimitation and type(useLimitation) == list:
776        md_legalconstraints.useLimitation = useLimitation
777    if accessConstrains and type(accessConstrains) == list:
778        md_legalconstraints.accessConstrains = accessConstrains       
779    return md_legalconstraints
780
781def create_md_identifier(code, authority = None):
782    """
783        Creates a new MD_Identifier
784        @param code: a String
785        @param authority: a CI_Citation instance
786    """
787    md_identifier = MD_Identifier()
788    if code == None:
789        raise Exception('NoNullableElement')
790    md_identifier.code = code
791    if authority:
792        md_identifier.authority = authority
793    return md_identifier
794
795def create_ci_responsible_party(role, organizationName = None, individualName = None):
796    """
797        Creates a new CI_ResponsibeParty
798        @param role: a CI_RoleCode
799    """
800    ci_responsible_party = CI_ResponsibleParty()
801    ci_responsible_party.role = role
802    if organizationName:
803        ci_responsible_party.organisationName = organizationName
804    if individualName:
805        ci_responsible_party.individualName = individualName   
806    return ci_responsible_party
807
808def create_md_metadata(date_stamp, contact, language = None):
809    """
810        Creates a new MD_Metadata
811        @param date_stamp: a Date instance
812        @param contacts: a CI_ResponsibleParty array instances
813        @param language: a string
814    """   
815    md_metadata = MD_Metadata()
816    md_metadata.dateStamp = date_stamp
817    for item in contact:
818        md_metadata.contact.append(item)
819    if language:
820        md_metadata.language = language   
821    return md_metadata
822
823def create_mo_online_resource(linkage, instance = None, name = None, function = None, \
824                            description = None, applicationProfile = None):
825    """
826        Creates a new CEDA_Result
827        @param linkage: the MO_OnlineResource.linkage.url.??? field
828        @param name: the MO_OnlineResource.linkage.name field
829        @param function: the MO_OnlineResource.function field
830        @param description: the MO_OnlineResource.description field
831        @param applicationProfile: the MO_OnlineResource.applicationProfile field
832    """
833    if instance is None:
834        on_line_resource = MO_OnlineResource()
835         
836    on_line_resource.linkage = linkage
837    if name and on_line_resource.name != name:         
838        on_line_resource.name = name
839    if function and on_line_resource.function != function:
840        on_line_resource.function = function
841    if description and on_line_resource.description != description:
842        on_line_resource.description = description
843    if applicationProfile and on_line_resource.applicationProfile != applicationProfile:
844        on_line_resource.applicationProfile = applicationProfile
845    return on_line_resource       
846
847def create_ceda_result(curation_category, internal_path, source = None):
848    """
849        Creates a new CEDA_Result
850        @param curation_category: a CEDA_CurationValue instance
851        @param internal_path: a String
852        @param source: an array of MO_OnlineResource instances
853    """
854    ceda_result = CEDA_Result()
855    ceda_result.curationCategory = curation_category
856    ceda_result.internalPath = internal_path           
857    if source: 
858        ceda_result.source = source
859    return ceda_result
860
861
862
863def create_dq_conformance_result(explanation, pass_, specification):
864    """
865        Creates a DQ_ConformanceResult instance
866        @param explanation: a String
867        @param pass_: a boolean value
868        @param specification: a CI_Citation instance 
869    """
870    dq_conformanceResult = DQ_ConformanceResult()
871    dq_conformanceResult.explanation = explanation
872    dq_conformanceResult.pass_ = pass_
873    dq_conformanceResult.specification = specification
874    return dq_conformanceResult
875
876def create_dq_element(result):
877    """
878        Creates a DQ_Element instance
879        @param result: a DQ_Result array (mix 1, max 2 items)
880    """
881    dq_element = DQ_Element()
882    if result and (type(result) == list) and (len(result) >= 1 and len(result) <= 2):
883        dq_element.result = result
884    return dq_element
885
886def create_ex_geographic_boundingbox(east, north, west, south):
887    """
888        Creates an EX_GeographicBoundingBox instance
889        @param east: the eastBoundLongitude attribute as float
890        @param north: the northBoundLongitude attribute as float
891        @param west: the westBoundLongitude attribute as float
892        @param south: the southBoundLongitude attribute as float               
893    """
894    ex_geographic_bb = EX_GeographicBoundingBox()
895    ex_geographic_bb.eastBoundLongitude = east
896    ex_geographic_bb.northBoundLatitude = north
897    ex_geographic_bb.westBoundLongitude = west
898    ex_geographic_bb.southBoundLatitude = south
899    return ex_geographic_bb
900   
901def create_ceda_processing():
902    ceda_processing = CEDA_Processing()
903    return ceda_processing
904
905
906def create_ceda_instrument():
907    ceda_instrument = CEDA_Instrument()
908    return ceda_instrument
909
910def create_ceda_composite_process():
911    ceda_cp = CEDA_CompositeProcess()
912    return ceda_cp
913
914def create_ceda_acquisition():
915    ceda_acquisition = CEDA_Acquisition()
916    return ceda_acquisition
917
918def create_ceda_review(reviewer, reviewFrequency, reviewStatus):
919    """
920        Returns a new CEDA_Review
921        @param reviewer: an MO_ResponsibilityPartyInfo
922        @param reviewFrequency: a CEDA_ReviewFrequencyValue
923        @param reviewStatus: a CEDA_ReviewStatusValue
924    """
925    ceda_review = CEDA_Review()
926    ceda_review.reviewer = reviewer
927    ceda_review.reviewFrequency = reviewFrequency
928    ceda_review.reviewStatus = reviewStatus           
929    return ceda_review
930
931def create_ceda_project(abstract = None, publication_state = None, \
932                       documentation = None, project_resource=None):
933    ceda_project = CEDA_Project()
934    if abstract:
935        ceda_project.abstract = abstract
936    if publication_state:
937        ceda_project.publicationState = publication_state       
938    if documentation and type(documentation) == list:
939        ceda_project.documentation = documentation
940    if project_resource and type(project_resource) == list:
941        ceda_project.projectResource = project_resource   
942    return ceda_project
943
944def from_date_string_to_pt(doc_phenomenon_time):
945    """
946        Transforms a date string like '2002-07-22' (startDate) in a TM_Instant instance or   
947        '2002-07-22/2011-08-06' (start/endDate) in a TM_Period instance
948        @param doc_phenomenon_time: a date string in the expected format
949    """
950    if doc_phenomenon_time:
951        pt = None
952        if '/' in doc_phenomenon_time:
953            period = doc_phenomenon_time.split('/')
954            begin_date = create_date(isoDateStringToTimeDate(period[0]))
955            begin_position = create_tm_position(date8601 = begin_date)
956            begin_tm_instant = create_tm_instant(begin_position)
957           
958            end_date = create_date(isoDateStringToTimeDate(period[1]))
959            end_position = create_tm_position(date8601 = end_date)
960            end_tm_instant = create_tm_instant(end_position)
961           
962            pt = create_tm_period(begin_tm_instant, end_tm_instant)
963        else:
964            tm_position = create_tm_position(date8601 = \
965                                            create_date(isoDateStringToTimeDate(doc_phenomenon_time)))
966            pt = create_tm_instant(tm_position)
967        return pt
968
969def from_pt_to_string(phenomenonTime):
970    """
971        Transforms a TM_Instant instance in a date string like '2002-07-22' (startDate) or   
972        a TM_Period instance in a string like '2002-07-22/2011-08-06' (start/endDate)
973        @param phenomenonTime: a aTM_Instace or a TM_Period instance
974        @return a pair startDate, endDate. If endDate does not exists return startDate,
975        None
976    """   
977    if phenomenonTime is None:
978        return None
979    startDate =None
980    endDate = None
981    if isinstance(phenomenonTime, TM_Instant):
982        startDate = _tm_InstantToString(phenomenonTime)
983    elif isinstance(phenomenonTime, TM_Period):
984        startDate = _tm_InstantToString(phenomenonTime.begin)       
985        endDate = _tm_InstantToString(phenomenonTime.end)
986    return startDate, endDate
987
988def compare_phenomenon_times(p1, p2):
989    s1 = from_pt_to_string(p1)
990    s2 = from_pt_to_string(p2)
991    return s1[0] == s2[0] and s1[1] == s2[1] 
992
993def _tm_InstantToString(tm_instant):
994    idate = tm_instant.position.date8601
995    return str(datetime.date(int(idate.year), int(idate.month), int(idate.day)))
996
997def _from_geographic_bb_to_string(gbb):
998    if gbb is None:
999        return None
1000    return '{0} {1},{2} {3}'.format(gbb.eastBoundLongitude, gbb.northBoundLatitude, \
1001                                    gbb.westBoundLongitude, gbb.southBoundLatitude)
1002   
1003def compareGeographicBoundingBoxes(gb1, gb2):
1004    return _from_geographic_bb_to_string(gb1) == _from_geographic_bb_to_string(gb2)
Note: See TracBrowser for help on using the repository browser.