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

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

Add simple object to stubB to represent selected items and retain the important
associated data.
Add new utility method, recreateListFromUnicode(string), to recreate the KML and
WMC URL lists passed via AJAX calls as unicode strings.

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 BeautifulSoup import BeautifulSoup
12from AccessControl import AccessControl
13from geoUtilities import Bounding
14from People import *
15from ndgObject 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 ndgRetrieve import ndgRetrieve
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                return xml
330         
331            def doit(self,xml):
332                layoutdir=self.c.get('layout','layoutdir')
333                x=stubB(xml,self.c)
334               
335         
336    unittest.main()
337           
338           
Note: See TracBrowser for help on using the repository browser.