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

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

Update ows_server code to use new ndgUtils module - and remove files that have
been migrated to this module.

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 SelectedItem:
83    ''' A simple object representing key info on selected items '''
84    def __init__(self,entryID,title,kmlURL,wmcURL):
85            self.entryID = entryID
86            self.title = title
87            self.kmlURL = kmlURL
88            self.wmcURL = wmcURL
89            self.kmlList = Utilities.recreateListFromUnicode(kmlURL)
90            self.wmcList = Utilities.recreateListFromUnicode(wmcURL)
91           
92class ObservationStation:
93    def __init__(self,h,e):
94        self.e=
95        self.hdg='Observation Station'
96        if e is None: return
97class DataProductionTool:
98    def __init__(self,h,e):
99        self.e=e
100        i=h.find(e,'dgInstrument')
101        if i is not None: 
102            self.hdg='Instrument'
103        else:
104            self.hdg='Model'
105        if e is None: return
106class Activity:
107    def __init__(self,h,e):
108        self.e=e
109        self.hdg='Activity'
110        if e is None: return
111       
112def Deployments(elem,helper,config):
113    ''' This is the late June 2007 version '''
114    if elem is None: return None
115    types={'dptList':'dataproductiontool','activityList':'activity','obsStnList':'observationstation','dataEntityList':'dataentity'}
116    names={'dptList':'Data Production Tools','activityList':'Activities','obsStnList':'Observation Stations','dataEntityList':'Data Entities'}
117    result={}
118    for alist in types:
119        blist=helper.find(elem,alist)
120        collection=[]
121        if blist is not None:
122            for object in blist:
123                uri=idconvert(helper,object,config=config)
124                name=helper.getText(object,'name')
125                shortName=helper.getText(object,'abbreviation')
126                collection.append((uri,name,shortName))
127            result[names[alist]]=collection
128    return result
129           
130def temporal(elem,helper):
131    ''' Parse for time coverage attributes '''
132    timeElems=helper.findall(elem,'*//dgTemporalCoverage')
133    tc=[]
134    for e in timeElems:
135        t=e.find('DateRange')
136        if t is not None:
137            c=[helper.getText(t,'DateRangeStart'),]
138            c.append(helper.getText(t,'DateRangeEnd'))
139        else:
140            c=[helper.getText(e,'DateSingle'),'']
141        c.append(helper.getText(elem,'*/dgDatasetStatus/dgDatasetClosure'))
142        tc.append(c)
143    return tc
144           
145def parseParameters(plist,helper):
146    ''' Takes a list of ET Parameter Summary elements, and parses them into a
147    sensible pythonic structure. In particular, given:
148    <dgParameterSummary>
149        <IsOutput>true</IsOutput>
150        <dgStdParameterMeasured>
151            <dgValidTerm>BAROCLINIC V_VELOCITY (OCEAN) CM/S</dgValidTerm>
152            <dgValidTermID>
153                <ParentListID>COAPEC_500YrRun_wholerun_decadal_ocean</ParentListID>
154                <TermID>null</TermID>
155            </dgValidTermID>
156        </dgStdParameterMeasured>
157        <ParameterName>BAROCLINIC V_VELOCITY (OCEAN) CM/S</ParameterName>
158    </dgParameterSummary>
159    we take the parameter name and the parentlistID and use them to build up a
160    parameter dictionary '''
161    ptypes={}
162    for p in plist:
163        ptype=helper.getText(p,'dgStdParameterMeasured/dgValidTermID/ParentListID')
164        if ptype not in ptypes: ptypes[ptype]=[]
165        ptypes[ptype].append(helper.getText(p,'ParameterName'))
166    gcmd='http://vocab.ndg.nerc.ac.uk/term/P111'
167    if gcmd in ptypes: 
168        dif=collapse2(ptypes[gcmd],split='/')
169        del ptypes[gcmd]
170    return dif,ptypes
171           
172class DataEntity:
173    def __init__(self,helper,element):
174        ''' Attempt to instantiate this stubB as a data entity'''
175        self.elem=element
176        self.helper=helper
177        #just one curator
178        self.curator=dgContact(self.elem.find('dgDataRoles/dgDataCurator'),ctype='organisation')
179        #possibly multiple creators
180        self.creators=[dgContact(i) for i in self.elem.findall('dgDataRoles/dgDataCreator')]
181        host,service = '','' # dummy for now
182        #possibly multiple granules
183        self.getGranules()
184        #bounding box, handled as a class because this is going to be difficult ...
185        self.bbox=Bounding(self.elem,helper,entity='moles')
186        self.timeCoverage=temporal(self.elem,self.helper)
187        #parameters
188        pelem=self.helper.findall(self.elem,'dgDataSummary/dgParameterSummary')
189        self.parameters,self.extraParameters=parseParameters(pelem,self.helper)
190        self.hdg='Data Entity'
191       
192    def getGranules(self):
193        ''' Load up the granule content within the entity '''
194        granList=self.elem.findall('dgDataGranule')
195        self.granules=[]
196        i=0
197        for item in granList:
198            i+=1
199            #following needs to be refactored when granule definition includes a proper name ...
200            name=wrapGetText(item,'dgGranuleSummary/dgGranuleName')
201            if name=='': name='Granule %s'%i
202            self.granules.append(dataGranule(self.helper,item,self.config,name=name))
203
204class dgMetadataDescription:
205   
206    def __init__(self,helper,elem,viewService):
207        ''' Initialise a Metadata Description '''
208        n=idconvert(helper,elem)
209        self.uri=n.uri
210        self.logo=None
211        self.abstract=helper.getText(elem,'abstract/abstractText')
212        self.texts=[]
213        self.onlineRefs=[]
214        for e in helper.findall(elem,'descriptionSection'):
215            textElem=helper.find(e,'dgDescriptionText')
216            if textElem is not None:
217                text=(textElem.text or '')
218                tail=''
219                for i in textElem: 
220                    text+=ET.tostring(i)
221                    tail=(i.tail or '')
222                text+=tail
223                ctype=helper.getText(e,'contentType')
224                if ctype in ['','text/html']:
225                    soup=BeautifulSoup(text)
226                    text=soup.prettify()
227                self.texts.append((text,ctype))
228        online=helper.findall(elem,'descriptionSection/descriptionOnlineReference/dgSimpleLink')
229        for o in online:
230            rtype=helper.getText(o,'name')
231            #url and uri supported in 1.4 moles, but no one has implemented that yet ...
232            uri,url=helper.getText(o,'URI'),helper.getText(o,'URL')
233            if rtype=='Logo':
234                self.logo=uri
235            else:
236                try:
237                    value=help
238                    self.onlineRefs.append((rtype,{'NumSim':'%s/%s'%(viewService,uri)}[rtype]))
239                except KeyError:
240                    self.onlineRefs.append((rtype,uri))
241
242
243class stubB(DataEntity,ObservationStation,DataProductionTool,Activity):
244       
245        ''' Holds the stub-b document and provides methods which get and manipulate it '''
246       
247        def __init__(self,elem,config):
248               
249                '''Instantiate with an element tree elem '''
250               
251                self.tree=elem
252                self.metadataType='NDG-B1'
253                self.services=[]
254                self.config=config
255                self.citation=''
256                self.personnel=[] # for DIF compatiability for the moment.
257                self.parameters={}
258                self.extraParameters={}
259                self.granules=[]
260                self.logos=[]
261               
262                try:
263                        helper=nsdumb(self.tree)
264                        self.name=helper.getText(self.tree,'name')
265                except Exception,e:
266                        raise ValueError('Error instantiating stubB [%s]'%e)
267
268                self.ndgObject=idconvert(helper,self.tree,self.config)
269                self.entryID=self.ndgObject.uri
270                self.viewService=self.ndgObject.viewService
271               
272                #Note that the root of the ElementTree instance is dgMetadataRecord
273                #so we don't need (or want) that in our xpath expressions.
274               
275                self.constraints=AccessControl(helper.find(self.tree,'dgMetadataSecurity'))
276                self.abbreviation=helper.getText(self.tree,'abbreviation')
277                if self.abbreviation=='': self.abbreviation=self.name[0:min(15,len(self.name))]
278                logos=helper.findall(self.tree,'dgMetadata/dgMetadatdataRecord/logos/logoURI')
279                for l in logos:
280                    self.logos.append((helper.find(l,'dgSimpleLink/name'),
281                                       helper.find(l,'dgSimpleLink/URI')))
282               
283                for i in ('dgDataEntity','dgActivity','dgDataProductionTool','dgObservationStation'):
284                    elem=helper.find(self.tree,i)
285                    if elem is not None: break
286                if elem is None:
287                    raise ValueError('StubB record does not contain an Activity, DE, DPT, ObsStn')
288                elif elem.tag=='dgDataEntity':
289                        DataEntity.__init__(self,helper,elem)
290                elif elem.tag=='dgActivity':
291                        Activity.__init__(self,helper,elem)
292                elif elem.tag=='dgDataProductionTool':
293                        DataProductionTool.__init__(self,helper,elem)
294                elif elem.tag=='dgObservationStation':
295                        ObservationStation.__init__(self,helper,elem)
296
297                self.description=dgMetadataDescription(
298                    helper,helper.find(self.tree,'dgMetadataDescription'),self.viewService)
299                if self.description.logo is not None:
300                    self.logos.append((('Logo',self.description.logo)))
301                    print 'LOGOS',self.logos
302                self.abstract=self.description.abstract
303                self.stubBtype=elem.tag
304               
305                # now go get all the related links
306               
307                self.related=Deployments(helper.find(elem,'DeploymentSummary'),helper,self.config)
308
309
310if __name__=="__main__":
311    import unittest
312    import os.path
313    from ndgUtils import ndgRetrieve, xmlHandler2
314       
315   
316    class TestCase(unittest.TestCase):
317   
318            def testDE(self):
319                ''' Test rendering a DataEntity stubB '''
320                doc='badc.nerc.ac.uk__NDG-B1__dataent_COAPEC'
321                xml=self.getit(doc)     
322                self.doit(xml.tree)
323               
324            def getit(self,doc):
325                self.c=myConfig('../../ndgDiscovery.config')
326                uri=ndgObject(doc)
327                status,xml=ndgRetrieve(uri,self.c)
328                self.assertEqual(status,1)
329                xml=xmlHandler2.xmlHandler(xml,string=1)
330                return xml
331         
332            def doit(self,xml):
333                layoutdir=self.c.get('layout','layoutdir')
334                x=stubB(xml,self.c)
335               
336         
337    unittest.main()
338           
339           
Note: See TracBrowser for help on using the repository browser.