source: TI07-MOLES/trunk/StubB/XSLT/browse/portal/cgi/stubB.py @ 825

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI07-MOLES/trunk/StubB/XSLT/browse/portal/cgi/stubB.py@825
Revision 825, 7.6 KB checked in by lawrence, 16 years ago (diff)

Better error handling, better xhtml compliance

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# BNL April 2006
6#
7import ElementTree as ET
8from insecure import *
9
10def wrapGetText(element,xpathExpression,multiple=0):
11        ''' Wraps a call to ET to get a text object in an error handler '''
12        if multiple:
13                r=element.findall(xpathExpression)
14        else:
15                r=[element.find(xpathExpression),]
16        try:
17                rr=[i.text for i in r]
18        except:
19                rr=['',]
20        if multiple: 
21                return rr
22        else: return rr[0] 
23       
24class Name:
25        ''' Handles the name type '''
26        def __init__(self,element):
27                if element is None:
28                        self.name=''
29                        return
30                if wrapGetText(element,'nameOrder')=='L2R':
31                        o=('title','initials','familyName')
32                else:
33                        o=('title','familyName','personalName')
34                self.name=''
35                for i in o: self.name+=' '+ wrapGetText(element,i)
36        def __str__(self):
37                return self.name
38       
39class dgContact:
40        '''A simple summary of contact information for an organisation or a person '''
41        #want to contract organisations and people into one simple type here ...
42        #This is moles 1.2.3 ... hopefully we can improve this ...
43        def __init__(self,element,ctype='org'):
44                ''' Instantiate a MOLES person element '''
45                self.elem=element
46                if self.elem is None: return
47                self.data={}
48                self.data['name']=Name(self.elem.find('dgRoleHolder/dgPerson/name'))
49                if ctype=='org':
50                        base='dgRoleHolder/dgOrganisation/'
51                else:
52                        base='dgRoleHolder/dgPerson/'
53                self.data['org']=wrapGetText(self.elem,base+'name')
54                self.data['email']=wrapGetText(self.elem,base+'contactDetails/eMail')
55                self.data['phone']=wrapGetText(self.elem,'contactDetails/telephone')
56                self.data['url']=wrapGetText(self.elem,'contactDetails/URI')
57        def toHTML(self):
58                ''' Convert to simple HTML '''
59                labels={'name':'','org':'Organisation: ','email':'Email: ','phone':'Phone: '}
60                html='<p>'
61                for item in ('name','org','email','phone'):
62                        if str(item) !='': html+='%s%s%s'%(labels[item],self.data[item],'<br/>')
63                html+='</p>'
64                return html
65               
66class Bounding:
67        ''' Separated out because this may change with versions '''
68        def __init__(self,elem):
69                '''Parse a data entity and load a bounding box '''
70                North=wrapGetText(elem,
71                        'dgDataSummary/dgDataCoverage/dgSpatialCoverage/BoundingBox/LimitNorth')
72                South=wrapGetText(elem,
73                        'dgDataSummary/dgDataCoverage/dgSpatialCoverage/BoundingBox/LimitSouth')
74                West=wrapGetText(elem,
75                        'dgDataSummary/dgDataCoverage/dgSpatialCoverage/BoundingBox/LimitWest')
76                East=wrapGetText(elem,
77                        'dgDataSummary/dgDataCoverage/dgSpatialCoverage/BoundingBox/LimitEast')
78                try:
79                        self.box=[float(i) for i in [North, South,West, East]]
80                except:
81                        self.box=None
82        def toHTML(self):
83                if self.box is not None:
84                        html='''<p>
85                                Limit North: %s <br/>
86                                Limit South: %s <br/>
87                                Limit West: %s <br/>
88                                Limit East: %s <br/>   
89                                </p>'''%self.box
90                else:
91                        html='No bounding box available'
92                return html     
93       
94class DataEntity:
95        def __init__(self,element):
96                ''' Attempt to instantiate this stubB as a data entity'''
97                self.elem=element
98                #just one curator
99                self.curator=dgContact(self.elem.find('dgDataRoles/dgDataCurator'),ctype='org')
100                #possibly multiple creators
101                self.creators=[dgContact(i) for i in self.elem.findall('dgDataRoles/dgDataCreator')]
102                host,service = '','' # dummy for now
103                #possibly multiple granules
104                self.granules=[self.bind2Aservice(host,service,i) for i in self.elem.findall('dgDataGranule')]
105                #bounding box, handled as a class because this is going to be difficult ...
106                self.bbox=Bounding(self.elem)
107                self.temporal()
108                #parameters
109                self.parameters=wrapGetText(self.elem,'dgDataSummary/dgParameterSummary/ParameterName',multiple=1)
110               
111        def temporal(self):
112                '''Instantiate the timeCoverage attribute by parsing for temporal coverage '''
113                t=self.elem.find('dgDataSummary/dgDataCoverage/dgTemporalCoverage/DateRange')
114                if t is not None:
115                        try:
116                                self.timeCoverage=[float(i.text) for i in t]
117                        except:
118                                self.timeCoverage='No time information'
119                else:
120                        t=self.elem.find('dgDataSummary/dgDataCoverage/dgTemporalCoverage/DateSingle')
121                        try:
122                                self.timeCoverage=t.text
123                        except:
124                                self.timeCoverage='No time information'
125               
126        def bind2Aservice(self,host,service,elem):
127                #dummy for now
128                return 'Alink'
129
130class stubB(DataEntity):
131        ''' Holds the stub-b document and provides methods which get and manipulate it '''
132        def __init__(self,uri,xsltMethod='JavaXalan'):
133                '''Instantiate by getting URI from exist database'''
134                self.xsltMethod=xsltMethod
135                self.metadataType='stubB'
136                self.labels={'activity':'Activity ','observationstation':'Observation Station ',
137                                        'dataproductiontool':'Data Production Tool ','dgDataEntity':'Data Entity '}
138                try:
139                        if xsltMethod=='JavaXalan':
140                                self.xml=insecureGetDoc(uri)
141                                if self.xml is not None:
142                                        self.tree=ET.fromstring(self.xml)
143                        else:
144                                self.tree=ET.parse(uri).getroot()
145                                self.xml=ET.tostring(self.tree)
146                        self.name=wrapGetText(self.tree,'name')
147                except:
148                        self.xml=None
149                        self.tree=None
150                        self.name='Not Found'
151                       
152                if self.xml is None: return
153                #note that the root of the ElementTree instance is dgMetadataRecord
154                #so we don't need (or want) that in our xpath expressions.
155                host='' #bodge
156                #this long ifelif sequence needs to go out of moles ...
157                elem=self.tree.find('dgDataEntity')
158                if elem is not None:
159                        DataEntity.__init__(self,elem)
160                        self.type='dgDataEntity'
161                        self.others=('activity','observationstation','dataproductiontool')
162                elem=self.tree.find('dgActivity')
163                if elem is not None:
164                        self.type='dgActivity'
165                        self.others=('dgDataEntity','observationstation','dataproductiontool')
166                elem=self.tree.find('dgDataProductionTool')
167                if elem is not None:
168                        self.type='dgDataProductionTool'
169                        self.others=('dgDataEntity','observationstation','activity')
170                elem=self.tree.find('dgObservationStation')
171                if elem is not None:
172                        self.type='dgObservationStation'
173                        self.others=('dgDataEntity','dataproductiontool','activity')
174               
175                else:
176                        #handle other forms
177                        pass
178                self.abstract=wrapGetText(self.tree,'dgMetadataDescription/abstract/abstractText')
179                service='cgi/browse.py'
180                self.Burl=self.bind2service(host,service,self.tree.find('dgMetadataID'))
181               
182                # now go get all the related links
183                self.related=[]
184                for related in self.tree.findall(self.type+'/RelatedDeployment'):
185                        deployment=['empty',[]]  #something should eventually go in the empty slot ...
186                        for item in self.others:
187                                subitems=related.findall(item)
188                                if subitems != []:
189                                        aa=[]
190                                        for subitem in subitems:
191                                                name=wrapGetText(subitem,'name')
192                                                url=self.bind2service(host,service,subitem.find('dgMetadataID'))
193                                                aa.append([name,url])
194                                        deployment[1].append([self.labels[item],aa])
195                        self.related.append(deployment)
196               
197        def bind2service(self,host,service,ndgElement):
198                '''Takes the various parts of an  id and bind to a service to produce a URL'''
199                ### very temporary code ###
200                try:
201                        repID=ndgElement.find('repositoryIdentifier').text
202                        url='%s/%s?uri=%s/%s'%(host,service,repID,ndgElement.find('localIdentifier').text)
203                        return url
204                except:
205                        return 'No link'
206       
207        def getSecurityDetails(self):
208                '''Obtain the roles a1nd attribute authority address'''
209                #issue an xquery on the stub-b
210                #parse for roles
211                #parse for AA WSDL
212                #tree=ElementTree.fromstring(self.xml)
213                #sec=tree.findall('//ndgSecurity')
214                roles=[]
215                AAaddress=''
216                return roles, AAaddress
217       
218        def toHTML(self):
219                x=doXSLT(self.xml,xsltMethod=self.xsltMethod)
220                return x
221       
222if __name__=="__main__":
223        x=stubB('../../exampleB/methyl.example.xml',xsltMethod='local')
224        for d in  x.related:print d
225        print x.name
226        print x.parameters
227        print x.timeCoverage
228        print x.bbox.toHTML()
229        print x.curator.toHTML()
230        for item in x.creators: print item.toHTML()
Note: See TracBrowser for help on using the repository browser.