source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/stubB.py @ 4177

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/stubB.py@4177
Revision 4177, 12.4 KB checked in by cbyrom, 11 years ago (diff)

Remove rogue print and import statements.

Line 
1#!/usr/bin/env python
2#
3# This python code (will) handle all forms of stub-B and provide HTML
4# methods to the extent required by the NDG browse functionality.
5# NB, It would be cleaner to use Dom's way of doing things but we'd
6# need a schema for that ...
7# BNL April 2006
8#
9
10from Utilities import *
11from ndgUtils.BeautifulSoup import BeautifulSoup
12from AccessControl import AccessControl
13from geoUtilities import Bounding
14from People import *
15from ndgUtils import ndgObject
16from ows_server.models import Utilities
17
18#from DeploymentHandling import *
19try: #python 2.5
20    from xml.etree import ElementTree as ET
21except ImportError:
22    try:
23        # if you've installed it yourself it comes this way
24        import ElementTree as ET
25    except ImportError:
26        # if you've egged it this is the way it comes
27        from elementtree import ElementTree as ET
28
29
30def collapse2(keywords,split='>'):
31    ''' Take the last element of a DIF parameter tree entry, and put them in a dictionary
32    under the DIF category '''
33    d={}
34    for item in keywords:
35        line=item.split(split)
36        category=line[0]
37        if category not in d: d[category]=[]
38        while line<>[]:
39            c=line.pop()
40            if c<>'': 
41                if c<>category:
42                    d[category].append(c)
43                line=[]
44    return d
45
46
47def idconvert(helper,elem,config=None,idelem='dgMetadataID'):
48    ''' Given an elementTree element for a dgMetadataID, create
49    a standard ndg URI, and produce an ndgObject '''
50    id=helper.find(elem,idelem)
51    entryID='%s__%s__%s'%(helper.getText(id,'repositoryIdentifier'),
52                            helper.getText(id,'schemeIdentifier'),
53                            helper.getText(id,'localIdentifier'))
54    uri=ndgObject(entryID,config)
55    return uri
56
57class ndgLink:
58    ''' This is a holder for an ndgObject which has a name (and possibly abbreviation) '''
59    def __init__(self,name,abbrev,ndgO,label='',image=None):
60        self.ndgObject=ndgO
61        self.name=name
62        self.abbrev=abbrev
63        self.image=image
64        self.label=label
65        self.URL=ndgO.BURL
66    def toHTML(self):
67        ### needs to be finished
68        return self.ndgObject.URL
69
70class dataGranule:
71        ''' Provides support for data granule structures '''
72        def __init__(self,helper,elem,config,name=''):
73            self.elem=elem
74            self.constraints=AccessControl(helper.find(elem,'accessControlPolicy'))
75            self.name=name
76            self.uri=idconvert(helper,elem,config,idelem='dataModelID')
77            self.entryID=self.uri.uri
78            self.bbox=Bounding(self.elem,helper,entity='moles')
79            self.timeCoverage=temporal(self.elem,helper)
80            self.parameters=helper.getText(elem,'dgGranuleSummary/dgParameterSummary/ParameterName',multiple=1)
81           
82class ObservationStation:
83    def __init__(self,h,e):
84        self.e=
85        self.hdg='Observation Station'
86        if e is None: return
87class DataProductionTool:
88    def __init__(self,h,e):
89        self.e=e
90        i=h.find(e,'dgInstrument')
91        if i is not None: 
92            self.hdg='Instrument'
93        else:
94            self.hdg='Model'
95        if e is None: return
96class Activity:
97    def __init__(self,h,e):
98        self.e=e
99        self.hdg='Activity'
100        if e is None: return
101       
102def Deployments(elem,helper,config):
103    ''' This is the late June 2007 version '''
104    if elem is None: return None
105    types={'dptList':'dataproductiontool','activityList':'activity','obsStnList':'observationstation','dataEntityList':'dataentity'}
106    names={'dptList':'Data Production Tools','activityList':'Activities','obsStnList':'Observation Stations','dataEntityList':'Data Entities'}
107    result={}
108    for alist in types:
109        blist=helper.find(elem,alist)
110        collection=[]
111        if blist is not None:
112            for object in blist:
113                uri=idconvert(helper,object,config=config)
114                name=helper.getText(object,'name')
115                shortName=helper.getText(object,'abbreviation')
116                collection.append((uri,name,shortName))
117            result[names[alist]]=collection
118    return result
119           
120def temporal(elem,helper):
121    ''' Parse for time coverage attributes '''
122    timeElems=helper.findall(elem,'*//dgTemporalCoverage')
123    tc=[]
124    for e in timeElems:
125        t=e.find('DateRange')
126        if t is not None:
127            c=[helper.getText(t,'DateRangeStart'),]
128            c.append(helper.getText(t,'DateRangeEnd'))
129        else:
130            c=[helper.getText(e,'DateSingle'),'']
131        c.append(helper.getText(elem,'*/dgDatasetStatus/dgDatasetClosure'))
132        tc.append(c)
133    return tc
134           
135def parseParameters(plist,helper):
136    ''' Takes a list of ET Parameter Summary elements, and parses them into a
137    sensible pythonic structure. In particular, given:
138    <dgParameterSummary>
139        <IsOutput>true</IsOutput>
140        <dgStdParameterMeasured>
141            <dgValidTerm>BAROCLINIC V_VELOCITY (OCEAN) CM/S</dgValidTerm>
142            <dgValidTermID>
143                <ParentListID>COAPEC_500YrRun_wholerun_decadal_ocean</ParentListID>
144                <TermID>null</TermID>
145            </dgValidTermID>
146        </dgStdParameterMeasured>
147        <ParameterName>BAROCLINIC V_VELOCITY (OCEAN) CM/S</ParameterName>
148    </dgParameterSummary>
149    we take the parameter name and the parentlistID and use them to build up a
150    parameter dictionary '''
151    ptypes={}
152    dif={}
153    for p in plist:
154        ptype=helper.getText(p,'dgStdParameterMeasured/dgValidTermID/ParentListID')
155        if ptype not in ptypes: ptypes[ptype]=[]
156        ptypes[ptype].append(helper.getText(p,'ParameterName'))
157    gcmd='http://vocab.ndg.nerc.ac.uk/term/P111'
158    if gcmd in ptypes: 
159        dif=collapse2(ptypes[gcmd],split='/')
160        del ptypes[gcmd]
161    return dif,ptypes
162           
163class DataEntity:
164    def __init__(self,helper,element):
165        ''' Attempt to instantiate this stubB as a data entity'''
166        self.elem=element
167        self.helper=helper
168        #just one curator
169        self.curator=dgContact(self.elem.find('dgDataRoles/dgDataCurator'),ctype='organisation')
170        #possibly multiple creators
171        self.creators=[dgContact(i) for i in self.elem.findall('dgDataRoles/dgDataCreator')]
172        host,service = '','' # dummy for now
173        #possibly multiple granules
174        self.getGranules()
175        #bounding box, handled as a class because this is going to be difficult ...
176        self.bbox=Bounding(self.elem,helper,entity='moles')
177        self.timeCoverage=temporal(self.elem,self.helper)
178        #parameters
179        pelem=self.helper.findall(self.elem,'dgDataSummary/dgParameterSummary')
180        self.parameters,self.extraParameters=parseParameters(pelem,self.helper)
181        self.hdg='Data Entity'
182       
183    def getGranules(self):
184        ''' Load up the granule content within the entity '''
185        granList=self.elem.findall('dgDataGranule')
186        self.granules=[]
187        i=0
188        for item in granList:
189            i+=1
190            #following needs to be refactored when granule definition includes a proper name ...
191            name=wrapGetText(item,'dgGranuleSummary/dgGranuleName')
192            if name=='': name='Granule %s'%i
193            self.granules.append(dataGranule(self.helper,item,self.config,name=name))
194
195class dgMetadataDescription:
196   
197    def __init__(self,helper,elem,viewService):
198        ''' Initialise a Metadata Description '''
199        n=idconvert(helper,elem)
200        self.uri=n.uri
201        self.logo=None
202        self.abstract=helper.getText(elem,'abstract/abstractText')
203        self.texts=[]
204        self.onlineRefs=[]
205        for e in helper.findall(elem,'descriptionSection'):
206            textElem=helper.find(e,'dgDescriptionText')
207            if textElem is not None:
208                text=(textElem.text or '')
209                tail=''
210                for i in textElem: 
211                    text+=ET.tostring(i)
212                    tail=(i.tail or '')
213                text+=tail
214                ctype=helper.getText(e,'contentType')
215                if ctype in ['','text/html']:
216                    soup=BeautifulSoup(text)
217                    text=soup.prettify()
218                self.texts.append((text,ctype))
219        online=helper.findall(elem,'descriptionSection/descriptionOnlineReference/dgSimpleLink')
220        for o in online:
221            rtype=helper.getText(o,'name')
222            #url and uri supported in 1.4 moles, but no one has implemented that yet ...
223            uri,url=helper.getText(o,'URI'),helper.getText(o,'URL')
224            if rtype=='Logo':
225                self.logo=uri
226            else:
227                try:
228                    value=help
229                    self.onlineRefs.append((rtype,{'NumSim':'%s/%s'%(viewService,uri)}[rtype]))
230                except KeyError:
231                    self.onlineRefs.append((rtype,uri))
232
233
234class stubB(DataEntity,ObservationStation,DataProductionTool,Activity):
235       
236        ''' Holds the stub-b document and provides methods which get and manipulate it '''
237       
238        def __init__(self,elem,config):
239               
240                '''Instantiate with an element tree elem '''
241               
242                self.tree=elem
243                self.metadataType='NDG-B1'
244                self.services=[]
245                self.config=config
246                self.citation=''
247                self.personnel=[] # for DIF compatiability for the moment.
248                self.parameters={}
249                self.extraParameters={}
250                self.granules=[]
251                self.logos=[]
252               
253                try:
254                        helper=nsdumb(self.tree)
255                        self.name=helper.getText(self.tree,'name')
256                except Exception,e:
257                        raise ValueError('Error instantiating stubB [%s]'%e)
258
259                self.ndgObject=idconvert(helper,self.tree,self.config)
260                self.entryID=self.ndgObject.uri
261                self.viewService=self.ndgObject.viewService
262               
263                #Note that the root of the ElementTree instance is dgMetadataRecord
264                #so we don't need (or want) that in our xpath expressions.
265               
266                self.constraints=AccessControl(helper.find(self.tree,'dgMetadataSecurity'))
267                self.abbreviation=helper.getText(self.tree,'abbreviation')
268                if self.abbreviation=='': self.abbreviation=self.name[0:min(15,len(self.name))]
269                logos=helper.findall(self.tree,'dgMetadata/dgMetadatdataRecord/logos/logoURI')
270                for l in logos:
271                    self.logos.append((helper.find(l,'dgSimpleLink/name'),
272                                       helper.find(l,'dgSimpleLink/URI')))
273               
274                for i in ('dgDataEntity','dgActivity','dgDataProductionTool','dgObservationStation'):
275                    elem=helper.find(self.tree,i)
276                    if elem is not None: break
277                if elem is None:
278                    raise ValueError('StubB record does not contain an Activity, DE, DPT, ObsStn')
279                elif elem.tag=='dgDataEntity':
280                        DataEntity.__init__(self,helper,elem)
281                elif elem.tag=='dgActivity':
282                        Activity.__init__(self,helper,elem)
283                elif elem.tag=='dgDataProductionTool':
284                        DataProductionTool.__init__(self,helper,elem)
285                elif elem.tag=='dgObservationStation':
286                        ObservationStation.__init__(self,helper,elem)
287
288                self.description=dgMetadataDescription(
289                    helper,helper.find(self.tree,'dgMetadataDescription'),self.viewService)
290                if self.description.logo is not None:
291                    self.logos.append((('Logo',self.description.logo)))
292                self.abstract=self.description.abstract
293                self.stubBtype=elem.tag
294               
295                # now go get all the related links
296               
297                self.related=Deployments(helper.find(elem,'DeploymentSummary'),helper,self.config)
298
299
300if __name__=="__main__":
301    import unittest
302    import os.path
303    from ndgUtils import ndgRetrieve, xmlHandler2
304       
305   
306    class TestCase(unittest.TestCase):
307   
308            def testDE(self):
309                ''' Test rendering a DataEntity stubB '''
310                doc='badc.nerc.ac.uk__NDG-B1__dataent_COAPEC'
311                xml=self.getit(doc)     
312                self.doit(xml.tree)
313               
314            def getit(self,doc):
315                self.c=myConfig('../../ndgDiscovery.config')
316                uri=ndgObject(doc)
317                status,xml=ndgRetrieve(uri,self.c)
318                self.assertEqual(status,1)
319                xml=xmlHandler2.xmlHandler(xml,string=1)
320                return xml
321         
322            def doit(self,xml):
323                layoutdir=self.c.get('layout','layoutdir')
324                x=stubB(xml,self.c)
325               
326         
327    unittest.main()
328           
329           
Note: See TracBrowser for help on using the repository browser.