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

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

Support for viewing xhtml description sections within stub-B

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
16#from DeploymentHandling import *
17try: #python 2.5
18    from xml.etree import ElementTree as ET
19except ImportError:
20    try:
21        # if you've installed it yourself it comes this way
22        import ElementTree as ET
23    except ImportError:
24        # if you've egged it this is the way it comes
25        from elementtree import ElementTree as ET
26
27
28def collapse2(keywords,split='>'):
29    ''' Take the last element of a DIF parameter tree entry, and put them in a dictionary
30    under the DIF category '''
31    d={}
32    for item in keywords:
33        line=item.split(split)
34        category=line[0]
35        if category not in d: d[category]=[]
36        while line<>[]:
37            c=line.pop()
38            if c<>'': 
39                if c<>category:
40                    d[category].append(c)
41                line=[]
42    return d
43
44
45def idconvert(helper,elem,config=None,idelem='dgMetadataID'):
46    ''' Given an elementTree element for a dgMetadataID, create
47    a standard ndg URI, and produce an ndgObject '''
48    id=helper.find(elem,idelem)
49    entryID='%s__%s__%s'%(helper.getText(id,'repositoryIdentifier'),
50                            helper.getText(id,'schemeIdentifier'),
51                            helper.getText(id,'localIdentifier'))
52    uri=ndgObject(entryID,config)
53    return uri
54
55class ndgLink:
56    ''' This is a holder for an ndgObject which has a name (and possibly abbreviation) '''
57    def __init__(self,name,abbrev,ndgO,label='',image=None):
58        self.ndgObject=ndgO
59        self.name=name
60        self.abbrev=abbrev
61        self.image=image
62        self.label=label
63        self.URL=ndgO.BURL
64    def toHTML(self):
65        ### needs to be finished
66        return self.ndgObject.URL
67
68class dataGranule:
69        ''' Provides support for data granule structures '''
70        def __init__(self,helper,elem,config,name=''):
71            self.elem=elem
72            self.constraints=AccessControl(helper.find(elem,'accessControlPolicy'))
73            self.name=name
74            self.uri=idconvert(helper,elem,config,idelem='dataModelID')
75            self.entryID=self.uri.uri
76
77class ObservationStation:
78    def __init__(self,h,e):
79        self.e=
80        self.hdg='Obsevation Station'
81        if e is None: return
82class DataProductionTool:
83    def __init__(self,h,e):
84        self.e=e
85        i=h.find(e,'dgInstrument')
86        if i is not None: 
87            self.hdg='Instrument'
88        else:
89            self.hdg='Model'
90        if e is None: return
91class Activity:
92    def __init__(self,h,e):
93        self.e=e
94        self.hdg='Activity'
95        if e is None: return
96       
97def Deployments(elem,helper,config):
98    ''' This is the late June 2007 version '''
99    if elem is None: return None
100    types={'dptList':'dataproductiontool','activityList':'activity','obsStnList':'observationstation','dataEntityList':'dataentity'}
101    names={'dptList':'Data Production Tools','activityList':'Activities','obsStnList':'Observation Stations','dataEntityList':'Data Entities'}
102    result={}
103    for alist in types:
104        blist=helper.find(elem,alist)
105        collection=[]
106        if blist is not None:
107            for object in blist:
108                uri=idconvert(helper,object,config=config)
109                name=helper.getText(object,'name')
110                shortName=helper.getText(object,'abbreviation')
111                collection.append((uri,name,shortName))
112            result[names[alist]]=collection
113    return result
114           
115class DataEntity:
116    def __init__(self,helper,element):
117        ''' Attempt to instantiate this stubB as a data entity'''
118        self.elem=element
119        self.helper=helper
120        #just one curator
121        self.curator=dgContact(self.elem.find('dgDataRoles/dgDataCurator'),ctype='organisation')
122        #possibly multiple creators
123        self.creators=[dgContact(i) for i in self.elem.findall('dgDataRoles/dgDataCreator')]
124        host,service = '','' # dummy for now
125        #possibly multiple granules
126        self.getGranules()
127        #bounding box, handled as a class because this is going to be difficult ...
128        self.bbox=Bounding(self.elem,entity='stubB')
129        self.timeCoverage=self.temporal()
130        print 'BOUNDING',self.bbox,self.timeCoverage
131        #parameters
132        plist=wrapGetText(self.elem,'dgDataSummary/dgParameterSummary/ParameterName',multiple=1)
133        self.parameters=collapse2(plist,split='/')
134        self.hdg='Data Entity'
135             
136       
137    def getGranules(self):
138        ''' Load up the granule content within the entity '''
139        granList=self.elem.findall('dgDataGranule')
140        self.granules=[]
141        i=0
142        for item in granList:
143            i+=1
144            #following needs to be refactored when granule definition includes a proper name ...
145            name=wrapGetText(item,'dgGranuleSummary/dgGranuleName')
146            if name=='': name='Granule %s'%i
147            self.granules.append(dataGranule(self.helper,item,self.config,name=name))
148               
149    def temporal(self):
150        '''Instantiate the timeCoverage attribute by parsing for temporal coverage '''
151        t=self.elem.find('dgDataSummary/dgDataCoverage/dgTemporalCoverage/DateRange')
152        if t is not None:
153            c=[self.helper.getText(t,'DateRangeStart'),]
154            c.append(self.helper.getText(t,'DateRangeEnd'))
155        else:
156            c=[self.helper.getText(self.elem,
157                    'dgDataSummary/dgDataCoverage/dgTemporalCoverage/DateSingle'),'']
158        c.append(self.helper.getText(self.elem,'dgDataSummary/dgDatasetStatus/dgDatasetClosure'))
159        return c
160
161class dgMetadataDescription:
162   
163    def __init__(self,helper,elem,viewService):
164        ''' Initialise a Metadata Description '''
165        n=idconvert(helper,elem)
166        self.uri=n.uri
167        self.logo=None
168        self.abstract=helper.getText(elem,'abstract/abstractText')
169        self.texts=[]
170        self.onlineRefs=[]
171        for e in helper.findall(elem,'descriptionSection'):
172            textElem=helper.find(e,'dgDescriptionText')
173            if textElem is not None:
174                text=textElem.text
175                tail=''
176                for i in textElem: 
177                    text+=ET.tostring(i)
178                    tail=i.tail
179                text+=tail
180                ctype=helper.getText(e,'contentType')
181                if ctype in ['','text/html']:
182                    soup=BeautifulSoup(text)
183                    text=soup.prettify()
184                self.texts.append((text,ctype))
185        online=helper.findall(elem,'descriptionSection/descriptionOnlineReference/dgSimpleLink')
186        for o in online:
187            rtype=helper.getText(o,'name')
188            #url and uri supported in 1.4 moles, but no one has implemented that yet ...
189            uri,url=helper.getText(o,'URI'),helper.getText(o,'URL')
190            if rtype=='Logo':
191                self.logo=uri
192            else:
193                try:
194                    value=help
195                    self.onlineRefs.append((rtype,{'NumSim':'%s/%s'%(viewService,uri)}[rtype]))
196                except KeyError:
197                    self.onlineRefs.append((rtype,uri))
198
199
200class stubB(DataEntity,ObservationStation,DataProductionTool,Activity):
201       
202        ''' Holds the stub-b document and provides methods which get and manipulate it '''
203       
204        def __init__(self,elem,config):
205               
206                '''Instantiate with an element tree elem '''
207               
208                self.tree=elem
209                self.metadataType='NDG-B1'
210                self.services=[]
211                self.config=config
212                self.citation=''
213                self.personnel=[] # for DIF compatiability for the moment.
214                self.parameters=None
215                self.granules=[]
216                self.logos=[]
217               
218               
219                try:
220                        helper=nsdumb(self.tree)
221                        self.name=helper.getText(self.tree,'name')
222                except Exception,e:
223                        raise ValueError('Error instantiating stubB [%s]'%e)
224
225                self.ndgObject=idconvert(helper,self.tree,self.config)
226                self.entryID=self.ndgObject.uri
227                self.viewService=self.ndgObject.viewService
228               
229                #Note that the root of the ElementTree instance is dgMetadataRecord
230                #so we don't need (or want) that in our xpath expressions.
231               
232                self.constraints=AccessControl(helper.find(self.tree,'dgMetadataSecurity'))
233                self.abbreviation=helper.getText(self.tree,'abbreviation')
234                if self.abbreviation=='': self.abbreviation=self.name[0:min(15,len(self.name))]
235                logos=helper.findall(self.tree,'dgMetadata/dgMetadatdataRecord/logos/logoURI')
236                for l in logos:
237                    self.logos.append((helper.find(l,'dgSimpleLink/name'),
238                                       helper.find(l,'dgSimpleLink/URI')))
239               
240                for i in ('dgDataEntity','dgActivity','dgDataProductionTool','dgObservationStation'):
241                    elem=helper.find(self.tree,i)
242                    if elem is not None: break
243                if elem is None:
244                    raise ValueError('StubB record does not contain an Activity, DE, DPT, ObsStn')
245                elif elem.tag=='dgDataEntity':
246                        DataEntity.__init__(self,helper,elem)
247                elif elem.tag=='dgActivity':
248                        Activity.__init__(self,helper,elem)
249                elif elem.tag=='dgDataProductionTool':
250                        DataProductionTool.__init__(self,helper,elem)
251                elif elem.tag=='dgObservationStation':
252                        ObservationStation.__init__(self,helper,elem)
253
254                self.description=dgMetadataDescription(
255                    helper,helper.find(self.tree,'dgMetadataDescription'),self.viewService)
256                if self.description.logo is not None:
257                    self.logos.append((('Logo',self.description.logo)))
258                    print 'LOGOS',self.logos
259                self.abstract=self.description.abstract
260                self.stubBtype=elem.tag
261               
262                # now go get all the related links
263               
264                self.related=Deployments(helper.find(elem,'DeploymentSummary'),helper,self.config)
265
266
267if __name__=="__main__":
268    import unittest
269    import os.path
270   
271    de='examples/badc.nerc.ac.uk__NDG-B1__dataent_chablis.xml'
272    dpt='examples/badc.nerc.ac.uk__NDG-B1__dpt_11634276941110630.xml'
273   
274    class TestCase(unittest.TestCase):
275   
276            def testDE(self):
277                ''' Test rendering a DataEntity stubB '''
278                fname=de
279                self.doit(fname)
280               
281            def testDPT(self):
282                ''' Test rendering a Data Production Tool stubB '''
283                fname=dpt
284                self.doit(fname)
285               
286               
287            def doit(self,fname):
288                xml=open(fname,'r').read()
289                config=myConfig('ndgDiscovery.config')
290                layoutdir=config.get('layout','layoutdir')
291                x=stubB(xml,config)
292                y='''<?xml version="1.0" encoding="UTF-8"?>
293                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
294                    <html xmlsns="http://www.w3.org/1999/xhtml" xml:lang="en">
295                            <head>
296                                    <META http-equiv="Content-Type" content="text/xhtml; charset=iso-8859-1"/>
297                                    <title>stubB</title>
298                                    <LINK media="all, screen" href="%s/layout/ndg.css" type="text/css" rel="stylesheet"/>
299                            </head> '''%layoutdir+x.toHTML(config)
300                ff=fname+'-output.html'
301                f=file(ff,'w')
302                f.write(y)
303               
304   
305    unittest.main()
306           
307           
Note: See TracBrowser for help on using the repository browser.