source: documentViewer/MpdlXmlTextServer.py @ 506:67014399894d

elementtree
Last change on this file since 506:67014399894d was 506:67014399894d, checked in by casties, 12 years ago

cleaned out all 4suite code and weird methods.
fixed GIS places.

File size: 14.5 KB
Line 
1from OFS.SimpleItem import SimpleItem
2from Products.PageTemplates.PageTemplateFile import PageTemplateFile
3
4import xml.etree.ElementTree as ET
5
6import re
7import logging
8import urllib
9import base64
10
11from SrvTxtUtils import getInt, getText, getHttpData
12
13def serialize(node):
14    """returns a string containing an XML snippet of node"""
15    s = ET.tostring(node, 'UTF-8')
16    # snip off XML declaration
17    if s.startswith('<?xml'):
18        i = s.find('?>')
19        return s[i+3:]
20
21    return s
22
23
24class MpdlXmlTextServer(SimpleItem):
25    """TextServer implementation for MPDL-XML eXist server"""
26    meta_type="MPDL-XML TextServer"
27
28    manage_options=(
29        {'label':'Config','action':'manage_changeMpdlXmlTextServerForm'},
30       )+SimpleItem.manage_options
31   
32    manage_changeMpdlXmlTextServerForm = PageTemplateFile("zpt/manage_changeMpdlXmlTextServer", globals())
33       
34    def __init__(self,id,title="",serverUrl="http://mpdl-text.mpiwg-berlin.mpg.de/mpdl/interface/", serverName=None, timeout=40):
35        """constructor"""
36        self.id=id
37        self.title=title
38        self.timeout = timeout
39        if serverName is None:
40            self.serverUrl = serverUrl
41        else:
42            self.serverUrl = "http://%s/mpdl/interface/"%serverName
43       
44    def getHttpData(self, url, data=None):
45        """returns result from url+data HTTP request"""
46        return getHttpData(url,data,timeout=self.timeout)
47   
48    def getServerData(self, method, data=None):
49        """returns result from text server for method+data"""
50        url = self.serverUrl+method
51        return getHttpData(url,data,timeout=self.timeout)
52
53
54    def getPlacesOnPage(self, docinfo=None, pn=None):
55        """Returns list of GIS places of page pn"""
56        docpath = docinfo.get('textURLPath',None)
57        if not docpath:
58            return None
59
60        places=[]
61        text=self.getServerData("xpath.xql", "document=%s&xpath=//place&pn=%s"%(docpath,pn))
62        dom = ET.fromstring(text)
63        result = dom.findall(".//resultPage/place")
64        for l in result:
65            id = l.get("id")
66            name = l.text
67            place = {'id': id, 'name': name}
68            places.append(place)
69
70        return places
71   
72         
73    def processPageInfo(self, dom, docinfo, pageinfo):
74        """processes page info divs from dom and stores in docinfo and pageinfo"""
75        # assume first second level div is pageMeta
76        alldivs = dom.find("div")
77       
78        if alldivs is None or alldivs.get('class', '') != 'pageMeta':
79            logging.error("processPageInfo: pageMeta div not found!")
80            return
81       
82        for div in alldivs:
83            dc = div.get('class')
84           
85            # pageNumberOrig 
86            if dc == 'pageNumberOrig':
87                pageinfo['pageNumberOrig'] = div.text
88               
89            # pageNumberOrigNorm
90            elif dc == 'pageNumberOrigNorm':
91                pageinfo['pageNumberOrigNorm'] = div.text
92               
93            # pageHeaderTitle
94            elif dc == 'pageHeaderTitle':
95                pageinfo['pageHeaderTitle'] = div.text
96               
97            # numFigureEntries
98            elif dc == 'countFigureEntries':
99                docinfo['numFigureEntries'] = getInt(div.text)
100               
101            # numTocEntries
102            elif dc == 'countTocEntries':
103                # WTF: s1 = int(s)/30+1
104                docinfo['numTocEntries'] = getInt(div.text)
105               
106            # numPlaces
107            elif dc == 'countPlaces':
108                docinfo['numPlaces'] = getInt(div.text)
109               
110            # numTextPages
111            elif dc == 'countPages':
112                np = getInt(div.text)                   
113                if np > 0:
114                    docinfo['numTextPages'] = np
115                    if docinfo.get('numPages', 0) == 0:
116                        # seems to be text-only - update page count
117                        docinfo['numPages'] = np
118                        #pageinfo['end'] = min(pageinfo['end'], np)
119                        pageinfo['numgroups'] = int(np / pageinfo['groupsize'])
120                        if np % pageinfo['groupsize'] > 0:
121                            pageinfo['numgroups'] += 1
122       
123        #logging.debug("processPageInfo: pageinfo=%s"%repr(pageinfo))
124        return
125         
126           
127    def getTextPage(self, mode="text", pn=1, docinfo=None, pageinfo=None):
128        """returns single page from fulltext"""
129        logging.debug("getTextPage mode=%s, pn=%s"%(mode,pn))
130        # check for cached text -- but ideally this shouldn't be called twice
131        if pageinfo.has_key('textPage'):
132            logging.debug("getTextPage: using cached text")
133            return pageinfo['textPage']
134       
135        docpath = docinfo['textURLPath']
136        # just checking
137        if pageinfo['current'] != pn:
138            logging.warning("getTextPage: current!=pn!")
139           
140        # stuff for constructing full urls
141        url = docinfo['url']
142        urlmode = docinfo['mode']
143        sn = pageinfo.get('sn', None)
144        highlightQuery = pageinfo.get('highlightQuery', None)
145        tocMode = pageinfo.get('tocMode', None)
146        tocPN = pageinfo.get('tocPN',None)
147        characterNormalization = pageinfo.get('characterNormalization', None)
148       
149        selfurl = docinfo['viewerUrl']
150       
151        if mode == "dict" or mode == "text_dict":
152            # dict is called textPollux in the backend
153            textmode = "textPollux"
154        elif not mode:
155            # default is text
156            mode = "text"
157            textmode = "text"
158        else:
159            textmode = mode
160       
161        textParam = "document=%s&mode=%s&pn=%s&characterNormalization=%s"%(docpath,textmode,pn,characterNormalization)
162        if highlightQuery:
163            textParam +="&highlightQuery=%s&sn=%s"%(urllib.quote(highlightQuery),sn)           
164       
165        # fetch the page
166        pagexml = self.getServerData("page-fragment.xql",textParam)
167        dom = ET.fromstring(pagexml)
168        # extract additional info
169        self.processPageInfo(dom, docinfo, pageinfo)
170        # page content is in <div class="pageContent">
171        pagediv = None
172        # ElementTree 1.2 in Python 2.6 can't do div[@class='pageContent']
173        # so we look at the second level divs
174        alldivs = dom.findall("div")
175        for div in alldivs:
176            dc = div.get('class')
177            # page content div
178            if dc == 'pageContent':
179                pagediv = div
180                break
181       
182        # plain text mode
183        if mode == "text":
184            # get full url assuming documentViewer is parent
185            selfurl = self.getLink()
186            if pagediv is not None:
187                links = pagediv.findall(".//a")
188                for l in links:
189                    href = l.get('href')
190                    if href and href.startswith('#note-'):
191                        href = href.replace('#note-',"%s#note-"%selfurl)
192                        l.set('href', href)
193
194                return serialize(pagediv)
195           
196        # text-with-links mode
197        elif mode == "dict":
198            if pagediv is not None:
199                viewerurl = docinfo['viewerUrl']
200                selfurl = self.getLink()
201                # check all a-tags
202                links = pagediv.findall(".//a")
203                for l in links:
204                    href = l.get('href')
205                   
206                    if href:
207                        # is link with href
208                        if href.startswith('http://mpdl-proto.mpiwg-berlin.mpg.de/mpdl/interface/lt/wordInfo.xql'):
209                            # is dictionary link - change href (keeping parameters)
210                            l.set('href', href.replace('http://mpdl-proto.mpiwg-berlin.mpg.de/mpdl/interface/lt/wordInfo.xql','%s/template/viewer_wordinfo'%viewerurl))
211                            # add target to open new page
212                            l.set('target', '_blank')
213                                                         
214                        # TODO: is this needed?
215                        if href.startswith('http://mpdl-proto.mpiwg-berlin.mpg.de/mpdl/lt/lemma.xql'):
216                            selfurl = self.absolute_url()
217                            l.set('href', href.replace('http://mpdl-proto.mpiwg-berlin.mpg.de/mpdl/lt/lemma.xql','%s/head_main_lemma'%selfurl))
218                            l.set('target', '_blank')
219                            l.set('onclick',"popupWin = window.open(this.href, 'InfoWindow', 'menubar=no, location,width=500,height=600,top=180, left=700, toolbar=no, scrollbars=1'); return false;")
220                            l.set('ondblclick', 'popupWin.focus();')   
221                   
222                        if href.startswith('#note-'):
223                            # note link
224                            l.set('href', href.replace('#note-',"%s#note-"%selfurl))
225                             
226                return serialize(pagediv)
227           
228        # xml mode
229        elif mode == "xml":
230            if pagediv is not None:
231                return serialize(pagediv)
232           
233        # pureXml mode
234        elif mode == "pureXml":
235            if pagediv is not None:
236                return serialize(pagediv)
237                 
238        # gis mode
239        elif mode == "gis":
240            if pagediv is not None:
241                # check all a-tags
242                links = pagediv.findall(".//a")
243                # add our URL as backlink
244                selfurl = self.getLink()
245                doc = base64.b64encode(selfurl)
246                for l in links:
247                    href = l.get('href')
248                    if href:
249                        if href.startswith('http://mappit.mpiwg-berlin.mpg.de'):
250                            l.set('href', re.sub(r'doc=[\w+/=]+', 'doc=%s'%doc, href))
251                            l.set('target', '_blank')
252                           
253                return serialize(pagediv)
254                   
255        return None
256   
257
258    def getToc(self, mode="text", docinfo=None):
259        """loads table of contents and stores XML in docinfo"""
260        logging.debug("getToc mode=%s"%mode)
261        if mode == "none":
262            return docinfo
263             
264        if 'tocSize_%s'%mode in docinfo:
265            # cached toc
266            return docinfo
267       
268        docpath = docinfo['textURLPath']
269        # we need to set a result set size
270        pagesize = 1000
271        pn = 1
272        if mode == "text":
273            queryType = "toc"
274        else:
275            queryType = mode
276        # number of entries in toc
277        tocSize = 0
278        tocDiv = None
279        # fetch full toc
280        pagexml = self.getServerData("doc-query.xql","document=%s&queryType=%s&queryResultPageSize=%s&queryResultPN=%s"%(docpath,queryType, pagesize, pn))
281        dom = ET.fromstring(pagexml)
282        # page content is in <div class="queryResultPage">
283        pagediv = None
284        # ElementTree 1.2 in Python 2.6 can't do div[@class='queryResultPage']
285        alldivs = dom.findall("div")
286        for div in alldivs:
287            dc = div.get('class')
288            # page content div
289            if dc == 'queryResultPage':
290                pagediv = div
291               
292            elif dc == 'queryResultHits':
293                docinfo['tocSize_%s'%mode] = getInt(div.text)
294
295        if pagediv:
296            # store XML in docinfo
297            docinfo['tocXML_%s'%mode] = ET.tostring(pagediv, 'UTF-8')
298
299        return docinfo
300   
301    def getTocPage(self, mode="text", pn=None, start=None, size=None, pageinfo=None, docinfo=None):
302        """returns single page from the table of contents"""
303        logging.debug("getTocPage mode=%s, pn=%s"%(mode,pn))
304        if mode == "text":
305            queryType = "toc"
306        else:
307            queryType = mode
308           
309        # check for cached TOC
310        if not docinfo.has_key('tocXML_%s'%mode):
311            self.getToc(mode=mode, docinfo=docinfo)
312           
313        tocxml = docinfo.get('tocXML_%s'%mode, None)
314        if not tocxml:
315            logging.error("getTocPage: unable to find tocXML")
316            return "Error: no table of contents!"
317       
318        if size is None:
319            size = pageinfo.get('tocPageSize', 30)
320           
321        if start is None:
322            start = (pn - 1) * size
323
324        fulltoc = ET.fromstring(tocxml)
325       
326        if fulltoc:
327            # paginate
328            first = (start - 1) * 2
329            len = size * 2
330            del fulltoc[:first]
331            del fulltoc[len:]
332            tocdivs = fulltoc
333           
334            # check all a-tags
335            links = tocdivs.findall(".//a")
336            for l in links:
337                href = l.get('href')
338                if href:
339                    # take pn from href
340                    m = re.match(r'page-fragment\.xql.*pn=(\d+)', href)
341                    if m is not None:
342                        # and create new url (assuming parent is documentViewer)
343                        url = self.getLink('pn', m.group(1))
344                        l.set('href', url)
345                    else:
346                        logging.warning("getTocPage: Problem with link=%s"%href)
347                       
348            # fix two-divs-per-row with containing div
349            newtoc = ET.Element('div', {'class':'queryResultPage'})
350            for (d1,d2) in zip(tocdivs[::2],tocdivs[1::2]):
351                e = ET.Element('div',{'class':'tocline'})
352                e.append(d1)
353                e.append(d2)
354                newtoc.append(e)
355               
356            return serialize(newtoc)
357       
358        return "ERROR: no table of contents!"
359   
360   
361    def manage_changeMpdlXmlTextServer(self,title="",serverUrl="http://mpdl-text.mpiwg-berlin.mpg.de/mpdl/interface/",timeout=40,RESPONSE=None):
362        """change settings"""
363        self.title=title
364        self.timeout = timeout
365        self.serverUrl = serverUrl
366        if RESPONSE is not None:
367            RESPONSE.redirect('manage_main')
368       
369# management methods
370def manage_addMpdlXmlTextServerForm(self):
371    """Form for adding"""
372    pt = PageTemplateFile("zpt/manage_addMpdlXmlTextServer", globals()).__of__(self)
373    return pt()
374
375def manage_addMpdlXmlTextServer(self,id,title="",serverUrl="http://mpdl-text.mpiwg-berlin.mpg.de/mpdl/interface/",timeout=40,RESPONSE=None):
376#def manage_addMpdlXmlTextServer(self,id,title="",serverUrl="http://mpdl-text.mpiwg-berlin.mpg.de:30030/mpdl/interface/",timeout=40,RESPONSE=None):   
377    """add zogiimage"""
378    newObj = MpdlXmlTextServer(id,title,serverUrl,timeout)
379    self.Destination()._setObject(id, newObj)
380    if RESPONSE is not None:
381        RESPONSE.redirect('manage_main')
382       
383       
Note: See TracBrowser for help on using the repository browser.