source: exist/trunk/python/ndgUtils/eXistInterface.py @ 4483

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/exist/trunk/python/ndgUtils/eXistInterface.py@4483
Revision 4483, 7.9 KB checked in by cbyrom, 12 years ago (diff)

Add schemas to ndgXqueries object and add method to retrieve these + tidy up logic in a few other scripts.

Line 
1from eXistConnector import *
2from ndgXqueries import ndgXqueries
3import xmlHandler2, logging
4
5class ndg_eXist(eXistConnector):
6    ''' Adds ndg methods to a "standard" exist Connector '''
7   
8    ATOM_TARGET = 'Atom'
9    DEFAULT_ALL_VAL = 'All' # value used when specifying '*' in searches
10
11    def __init__(self,db='glue.badc.rl.ac.uk',passwordFile='passwords.txt'):
12        logging.debug("Initialising connection to eXist DB ('%s')" %db)
13        try:
14            f=file(passwordFile,'r')
15        except IOError,e:
16            raise IOError('%s [looking for %s in %s]'%(e,passwordFile,os.getcwd()))
17           
18        pw={}
19        for line in f.readlines():
20            host,userid,password=line.strip().split(' ')
21            pw[host]=(userid,password)
22        f.close()
23        if db not in pw:
24            raise ValueError('Unable to find eXist password for repository [%s]'%db)
25        eXistConstants = InstanceObject(host=db,
26                                userid=pw[db][0],
27                                password=pw[db][1],
28                                base_path="/exist/servlet",
29                                xmlrpc_base_path="/exist/xmlrpc",
30                                port=8080)
31       
32        eXistConnector.__init__(self,eXistConstants)
33        self.ids={}
34        logging.debug("Connection initialised")
35       
36       
37    def __buildquery(self,query,target=None):
38        '''Create an NDG full text query '''
39        if target is not None:
40            s='''let $hits := collection('/db/%s')//root()[. &= '%s'] ;
41                 for $i in $hits
42                    return <document>{document-uri($i)}</document>'''%(target,query)
43        else: s="/*[. &='%s']"%query
44
45        return s#xmlrpclib.Binary(s)
46
47    def __buildParamSearch(self,param,value,target):
48        s="for $x in document()//%s where $x[.%s &= '%s'] return $x"%(target,param,value)
49        return s
50
51    def full_text(self,query,target=None):
52        ''' Carry out a full text search within the "target" collection '''
53        id,summary=self.executeQuery(self.__buildquery(query,target))
54        self.ids[id]=0
55        return id,summary
56
57    def retrieveNext(self,id,pos=None):
58        ''' Takes a sessionID from an existing query and gets the next document '''
59        if pos is not None: self.ids[id]=pos
60        try:
61            r=self.retrieve(id, self.ids[id])
62            self.ids[id]+=1
63            return r
64        except xmlrpclib.Fault:
65            return None
66        except KeyError:
67            return None
68   
69    def sessionRelease(self,id):
70        ''' Releases a session and removes the position counter '''
71        try:
72            self.release(id)
73            del self.ids[id]
74            return 1
75        except:
76            return 0
77   
78    def chunkedFullText(self,query,start=1,number=10,target='DIF'):
79        ''' Execute a chunked full text query and return the result
80        set '''
81        return self.executeChunkedQuery(self.__buildquery(query,target),start,number,params={})
82   
83   
84    def getDIF(self,entryID):
85        ''' Get a specific DIF document from a repository by using the entryID '''
86        xq='''declare default element namespace 'http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/'; \
87            for $DE in collection()/DIF[Entry_ID='%s'] return $DE'''%entryID
88        xquery='''for $DE in collection('/db/testdif1')/DIF[Entry_ID='%s'] return $DE'''%entryID
89        id,summary=self.executeQuery(xq)#xquery)
90        if summary['hits']==1:
91            r=self.retrieve(id,0,{})
92            self.sessionRelease(id)
93        else:
94            r=summary['hits']
95        return r
96       
97    def search(self,term,start=1,howmany=20, \
98               target=None,scope=None,bbox=None, \
99               dateRange=None,geoSearchType=None, \
100               providerID=None, atomTypeID=None):
101        ''' Provides a search interface that mimics the WSDL search interface, except that
102        the target used is the exist collection name, and scope, bbox and dateRange are ignored,
103        and a python summary object is returned '''
104        #select the right query according to the docType
105       
106        if target == self.ATOM_TARGET:
107            xquery = self.__createAtomSearch(providerID, atomTypeID, term)
108        else:
109            xqName={'ndg_B_metadata':'molesSummary',\
110                'NumSim':'numsimSummary'}[target]
111            xquery=ndgXqueries()[xqName]
112            xquery=xquery.replace('SEARCHSTRING',term)
113       
114        logging.info("Executing xquery search")
115        logging.debug(" - query: '%s'" %xquery)
116        r=self.executeChunkedQuery(str(xquery),start,howmany)
117        logging.info("Search complete - processing results")
118        x=xmlHandler2.xmlHandler(str(r),string=1)
119        h=x.tree.get('hits')
120        self.results=[]
121        self.serverSessionID=''
122        if h is None:
123            self.hits=0
124            self.start=0
125            self.howmany=0
126            self.error=['No results for [%s]'%term,]
127        else:
128            self.hits=int(h)
129            self.error=None
130            self.start=int(x.tree.get('start'))
131            self.howmany=int(x.tree.get('count'))
132            slist=x.tree.findall('summary')
133            for s in slist:
134                t=edict(id=s.find('id').text,name=s.find('name').text,\
135                        type=s.find('type').text)
136                # add extra stuff for atom search (NB, this could be added to all
137                # but am unsure of implications elsewhere atm
138                if target == self.ATOM_TARGET:
139                    for key in ['providerID', 'created', 'href', 'subtype']:
140                        t[key] = s.find(key).text
141
142                        # adjust href to point to atom editor instead of atom view
143                        if key == 'href' and t[key]:
144                            t[key] = t[key].replace('view', 'editAtom')
145                           
146                        if key == 'subtype':
147                            t[key] = t[key]
148                   
149                self.results.append(t)
150        return self.results
151   
152
153    def __createAtomSearch(self, providerID, atomTypeID, term):
154        '''
155        Create a valid xquery search for searching atoms
156        '''
157        logging.debug("Creating xquery for searching atoms")
158        logging.debug("providerID: '%s', atomTypeID: '%s', term: '%s'" 
159                      %(providerID, atomTypeID, term))
160        xquery = "declare namespace moles='http://ndg.nerc.ac.uk/schema/moles2beta';\n" + \
161            "declare namespace atom='http://www.w3.org/2005/Atom';\n" + \
162            "for $DE in collection('/db/atoms')//root()["
163
164        # only add the required search clauses - NB, these increase the search time
165        # significantly, so avoid unless really required
166        whereClause = []
167        if term:
168            whereClause.append(". &= '" + term + "'")
169       
170        if providerID and providerID != self.DEFAULT_ALL_VAL:
171            whereClause.append("atom:entry/moles:entity/moles:molesISO/moles:providerID = '" + providerID + "'")
172       
173        if atomTypeID and atomTypeID != self.DEFAULT_ALL_VAL:
174            whereClause.append("atom:entry/atom:category/@label = '" + atomTypeID + "'")
175           
176        if not whereClause:
177            whereClause.append(".")
178       
179        for i, clause in enumerate(whereClause):
180            if i > 0:
181                xquery += " and "
182            xquery += clause
183           
184        xquery += "] return <summary> \
185<id>{$DE/atom:entry/atom:id/text()}</id> \
186<name>{$DE/atom:entry/atom:title/text()}</name> \
187<type>{string($DE/atom:entry/atom:category[@term='ATOM_TYPE']/@scheme)}</type> \
188<subtype>{string($DE/atom:entry/atom:category[@term='ATOM_SUBTYPE']/@scheme)}</subtype> \
189<href>{string($DE/atom:entry/atom:link[@rel='self']/@href)}</href> \
190<providerID>{$DE/atom:entry/moles:entity/moles:molesISO/moles:providerID/text()}</providerID> \
191<created>{$DE/atom:entry/moles:entity/moles:molesISO/moles:created/text()}</created> \
192</summary>"
193
194        logging.debug("Created xquery: '%s'" %xquery)
195        return xquery
Note: See TracBrowser for help on using the repository browser.