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

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

Simplify xquery search.

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