Annotation of ECHO_content/ECHO_helpers.py, revision 1.27

1.17      dwinter     1: import socket
1.15      dwinter     2: import urllib
1.21      dwinter     3: import xml.dom.minidom
1.24      dwinter     4: from types import *
1.25      dwinter     5: from Products.PageTemplates.PageTemplateFile import PageTemplateFile
                      6: from Globals import package_home
                      7: import os.path
                      8: 
                      9: displayTypes = ['ZSQLExtendFolder','ZSQLBibliography','ECHO_group','ECHO_collection','ECHO_resource','ECHO_link','ECHO_sqlElement','ECHO_pageTemplate','ECHO_externalLink','ImageCollectionIFrame','VLP_resource','VLP_essay','ECHO_ZCatalogElement','ImageCollection','versionedFileFolder']
                     10: 
                     11: def content_html(self,type):
                     12:         """template fuer content"""
                     13:         #templates = self.ZopeFind(self.aq_parent,obj_ids=[type+"_template"])
                     14:         #
                     15:         #if templates:
                     16:         #    return templates[0][1]()
                     17: 
                     18:         if hasattr(self,type+"_template"):
                     19:             obj=getattr(self,type+"_template")
                     20:             return obj()
                     21:         else:
                     22:             pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_%s_template_standard.zpt'%type).__of__(self)
                     23:             pt.content_type="text/html"
                     24:             return pt()
                     25:     
                     26:     
                     27: 
                     28: class ECHO_basis:
                     29:     """basis eigenschaften fuer echo objekte"""
1.26      dwinter    30:     def showRDF(self):
                     31:        """showrdf"""
                     32:             self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml')
                     33:        ret="""<?xml version="1.0" encoding="utf-8"?>\n<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  xmlns:ECHONAVIGATION="http://www.echo.eu/rdf#">\n"""
                     34:        ret+=self.getRDF(urn="echo:colllectionroot")+"\n"
                     35: 
                     36:        ret+="""</RDF:RDF>"""
                     37:            return ret 
                     38: 
                     39:   
                     40: 
                     41:     def createSubElementRDF(self,urn=None):
                     42:        """rdf list"""
                     43:        if not urn:
                     44:            urn=self.absolute_url()
                     45:        ret=""
                     46: 
                     47:        rettemp="""<RDF:Seq RDF:about="%s">\n"""%urn
                     48:        flag=0
                     49:        
                     50:        li="""<RDF:li RDF:resource="%s" />\n"""
                     51:        if not ('<error>' in self.getFullTextXML(noredirect='Yes')):
                     52:            nurn=self.absolute_url()+'/getFullTextXML'
                     53:            rettemp+=li%nurn
                     54:            flag=1
                     55:        if not ('<error>' in self.getImageView(noredirect='Yes')):
                     56:            nurn=self.absolute_url()+'/getImageView'
                     57:            rettemp+=li%nurn
                     58:            flag=1
                     59: 
                     60: 
                     61:        if not ('<error>' in self.showMetaDataXML()):
                     62:            nurn=self.absolute_url()+'/showMetaDataXML'
                     63:            rettemp+=li%nurn
                     64:            flag=1
                     65:            
                     66:        rettemp+="</RDF:Seq>"
                     67: 
                     68:        if flag==1:
                     69:            ret+=rettemp
                     70:            
                     71:        if not ('<error>' in self.getFullTextXML(noredirect='Yes')):
                     72:                     nurn=self.absolute_url()+'/getFullTextXML' 
                     73:            ret+=getRDFDescription(self,self.absolute_url()+'/getFullTextXML',urn=nurn,nameDef="Fulltext",typeName="ECHO_fulltext")
                     74: 
                     75:        if not ('<error>' in self.getImageView(noredirect='Yes')):
                     76:                     nurn=self.absolute_url()+'/getImageView'
                     77:            ret+=getRDFDescription(self,self.absolute_url()+'/getImageView',urn=nurn,nameDef="Image View",typeName="ECHO_imageview")
                     78:            
                     79:        if not ('<error>' in self.showMetaDataXML()):
                     80:                     nurn=self.absolute_url()+'/showMetaDataXML'
                     81:            ret+=getRDFDescription(self,self.absolute_url()+'/showMetaDataXML',urn=nurn,nameDef="Metadata",typeName="ECHO_metaData")
                     82: 
                     83:        return ret
                     84:        
1.25      dwinter    85:     def content_html(self,type="collection"):
                     86:        """template fuer content bei einbau und ECHO_Umgebung"""
                     87:        
                     88:        return content_html(self,type)
                     89:         
                     90:     def getTitle(self):
                     91:    """title"""
                     92:    try:
                     93:        return self.title.encode('utf-8','ignore') 
                     94:    except:
                     95:        self.title=self.title.decode('iso-8859-1','ignore')[0:] #correnct conding error
                     96:        return self.title.encode('utf-8','ignore') 
                     97:    
                     98:     def getLabel(self):
                     99:    """title"""
                    100:    try:
                    101:        return self.label.encode('utf-8','ignore') 
                    102:    except:
                    103:        self.label=self.label.decode('iso-8859-1','ignore')[0:] #correnct conding error
                    104:        return self.label.encode('utf-8','ignore') 
                    105:    
                    106:     
                    107:     def changeECHOEntriesForm(self):
                    108:         """change Entries for the ECHO Navigation environment"""
                    109:         pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeECHOEntriesForm')).__of__(self)
                    110:         return pt()
                    111:     
1.26      dwinter   112:     def changeECHOEntries(self,label,weight,description,queryString,RESPONSE=None):
1.25      dwinter   113:         """change Entries for the ECHO Navigation environment
                    114:         @param label: label fuer die Navigation"""
                    115:         self.label=label
                    116:         self.weight=weight
                    117:         self.description=description
1.26      dwinter   118:    self.queryString=queryString
1.25      dwinter   119:         
                    120:         if RESPONSE:
                    121:             RESPONSE.redirect("manage_main")
                    122: 
                    123:     manage_options=({'label':'change ECHO Navigation Entries','action':'changeECHOEntriesForm'},)
                    124: 
                    125:     #ende der echo erweiterungen
                    126: 
1.24      dwinter   127: 
                    128: def toList(field):
                    129:     """Einzelfeld in Liste umwandeln"""
                    130:     if type(field)==StringType:
                    131:         return [field]
                    132:     else:
                    133:         return field
1.21      dwinter   134: 
                    135: def getText(nodelist):
                    136: 
                    137:     rc = ""
                    138:     for node in nodelist:
                    139:        if node.nodeType == node.TEXT_NODE:
                    140:            rc = rc + node.data
                    141:     return rc
                    142: 
1.25      dwinter   143: def getTextFromNode(nodename):
                    144:     nodelist=nodename.childNodes
                    145:     rc = ""
                    146:     for node in nodelist:
                    147:        if node.nodeType == node.TEXT_NODE:
                    148:            rc = rc + node.data
                    149:     return rc
                    150: 
1.21      dwinter   151: 
                    152: def readFieldFromXML(meta_url,parent,field):
                    153:    """lesespezifisches metadatum"""
1.16      dwinter   154:    
1.21      dwinter   155:    try:
                    156:        dom=xml.dom.minidom.parse(meta_url)
                    157: 
                    158:    except:
1.22      dwinter   159:        try:
                    160:            fh=urllib.urlopen(meta_url)
                    161:            dom=xml.dom.minidom.parse(fh)
                    162:            except:
                    163:            return None
1.21      dwinter   164:    if not dom: return None
                    165: 
                    166:    parent=dom.getElementsByTagName(parent)
1.23      dwinter   167:    if not parent: return None
1.21      dwinter   168: 
                    169:    field=parent[0].getElementsByTagName(field)
                    170: 
                    171:    if not field: return None
                    172: 
                    173:    return getText(field[0].childNodes)
                    174:    
                    175:    
                    176:          
1.15      dwinter   177: def urlopen(url):
                    178:    """urlopen mit timeout"""
1.20      dwinter   179:    socket.setdefaulttimeout(2)
                    180:    ret=urllib.urlopen(url)
1.18      dwinter   181:    socket.setdefaulttimeout(5)
1.20      dwinter   182:    return ret
1.17      dwinter   183: #  urlopener = urllib.URLopener()
                    184: #
                    185: #  try:        
                    186: #      con = urlopener.open(url)
                    187: #      return con
                    188: #  except timeoutsocket.Timeout:
                    189: #      return None
1.15      dwinter   190: 
                    191: 
1.25      dwinter   192: 
1.11      dwinter   193: 
1.6       dwinter   194: 
1.14      dwinter   195: def checkOnlyOneInGroup(object): 
1.6       dwinter   196:    """check if object is a group and if it containt only one element it return this element"""
                    197:    displayedObjects=object.ZopeFind(object,obj_metatypes=displayTypes)
                    198:    if len(displayedObjects)==1: # nur ein Object dann redirect auf dieses Object
1.8       dwinter   199: 
1.6       dwinter   200:        return displayedObjects[0][1]
1.27    ! dwinter   201:    else:       return object
1.6       dwinter   202: 
1.27    ! dwinter   203: def getSubCols(self,sortfield="weight",subColTypes= displayTypes,sortFieldMD=None):
1.1       dwinter   204: 
1.27    ! dwinter   205:    def sortfnc(sortfield,x,y):
        !           206:        xa=x[1].getMDValue(sortfield)
        !           207:        ya=y[1].getMDValue(sortfield)
        !           208:        print xa,ya
        !           209:        return cmp(xa,ya)
        !           210:    
        !           211:    sortWithMD = lambda sortfield : (lambda x,y : sortfnc(sortfield,x,y))
1.1       dwinter   212:         ids=[]
1.6       dwinter   213:    displayedObjects=self.ZopeFind(self,obj_metatypes=subColTypes)
                    214:    
                    215:    
                    216:    for entry in displayedObjects:
1.25      dwinter   217:             
1.3       dwinter   218:             object=entry[1]
1.25      dwinter   219:             ids.append(object)
                    220: 
1.1       dwinter   221:         try:
                    222:             sortfield=self.sortfield
                    223:         except:
                    224:             """nothing"""
                    225:             
                    226:         tmplist=[]
                    227:         for x in ids:
                    228:             if hasattr(x,sortfield):
                    229:                 try:
1.7       dwinter   230: 
1.1       dwinter   231:                     x=int(x)
                    232:                 except:
                    233:                     """nothing"""
                    234:                 tmp=getattr(x,sortfield)
                    235:             else:
                    236:                 tmp=10000000
                    237:             tmplist.append((tmp,x))
1.25      dwinter   238: 
1.27    ! dwinter   239:    if not sortFieldMD:
        !           240:        tmplist.sort()
        !           241:    else:
        !           242:        tmplist.sort(sortWithMD(sortFieldMD))
        !           243:        
1.1       dwinter   244:         return [x for (key,x) in tmplist]
1.25      dwinter   245: 
                    246: def ECHO_rerenderLinksMD(self,obj=None,types=['title','label']):
                    247:         """Rerender all Links"""
                    248:    ret=""
                    249:    
                    250:         if not obj:
                    251:             obj = self
                    252:             
                    253:         entries=obj.ZopeFind(obj,obj_metatypes=['ECHO_resource'],search_sub=1)
                    254: 
                    255:         for entry in entries:
                    256:        if entry[1].meta_type == 'ECHO_resource':
                    257:            try:
                    258:                entry[1].ECHO_getResourceMD(template="no")
                    259:                                 if "title" in types:
                    260:                                     entry[1].generate_title()
                    261:                                 if "label" in types:
                    262:                                     entry[1].generate_label()
                    263:                ret+="OK:"+entry[0]+"-- "+entry[1].getTitle().decode('utf-8')+"-- "+entry[1].getTitle().decode('utf-8')+"<br>"
                    264:            except:
                    265:                ret+="Error:"+entry[0]+"<br>"
                    266: 
                    267:        
                    268:                 
                    269:                 
                    270:         return "<html><body>"+ret+"Rerenderd all links to resources in: "+self.title+"</html></body>"
                    271: 
                    272: def reloadMetaDataFromStorage(self,RESPONSE=None):
                    273:        """copy metadata from the storage to ECHO"""
                    274:        ret=""
                    275:        resources=self.ZopeFind(self,obj_metatypes=['ECHO_resource'],search_sub=1)
                    276: 
                    277:        for resource in resources:
                    278:            x=str(resource[1].copyIndex_meta2echo_resource())+"<br>"
                    279:            ret+=x
                    280:            #print x
                    281:            
                    282: 
                    283:        if RESPONSE is not None:
                    284:            #RESPONSE.redirect('./manage_main')
                    285:            return "<html><body>"+ret+"</html></body>"
                    286: 
                    287:        return ret
                    288:     
                    289: def getRDFDescription(self,linkURL,urn=None,nameDef=None,typeName=None):
                    290:        """rdf"""
                    291:        
                    292:        ret=""
                    293:        about="""<RDF:Description RDF:about="%s">"""
                    294:        name="""<ECHONAVIGATION:name>%s</ECHONAVIGATION:name>"""
                    295:        link="""<ECHONAVIGATION:link xlink:href="%s">%s</ECHONAVIGATION:link>"""
                    296:        clickable="""<ECHONAVIGATION:linkClickable>%s</ECHONAVIGATION:linkClickable>"""
                    297:        #link="""<ECHONAVIGATION:link RDF:about="%s"/>"""
                    298:        type="""<ECHONAVIGATION:type>%s</ECHONAVIGATION:type>"""
                    299:             #xlink="""<ECHONAVIGATION:xlink xlink:href="%s"/>"""   
                    300:        if not urn:
                    301:            #urn="urn:"+re.sub('/',':',self.absolute_url())
                    302:            urn=self.absolute_url()
                    303:        about2=about%urn
                    304:        if not nameDef:
                    305:            if hasattr(self,'label') and not (self.label==""):
                    306:                name2=name%self.label
                    307:            elif not self.title=="":
                    308:                name2=name%self.title
                    309:            else:
                    310:                name2=name%self.getId()
                    311: 
                    312:            name2=re.sub('&','&amp;',name2)
                    313:        else:
                    314:            name2=name%nameDef
                    315: 
                    316:        linkURL=re.sub('http:','',linkURL)
                    317:        linkURL2=re.sub('&','&amp;',linkURL)
                    318:        link2=link%(("http:"+linkURL2),("http:"+urllib.quote(linkURL)))
                    319:        clickable2=clickable%"true"
                    320: 
                    321:        if not typeName:
                    322:            type2=type%self.meta_type
                    323:        else:
                    324:            type2=type%typeName
                    325:        
                    326:        #ret=about2+"\n"+name2+"\n"+link2+"\n"+type2+"\n"+clickable2+"\n</RDF:Description>"
                    327:        ret=about2+"\n"+name2+"\n"+type2+"\n"+clickable2+"\n</RDF:Description>"
                    328:        return ret
                    329:     
                    330: def getCopyrightsFromForm(self,argv): 
                    331:    medias={}
                    332:    partners={}
                    333:    copyrights={}
                    334:    
                    335:    copyrightsFinal=[]
                    336:    for arg in argv.keys():
                    337:        
                    338:        if arg[0:5]=='media':
                    339:            nm=int(arg[5:])
                    340:            medias[nm]=argv[arg]
                    341:        elif arg[0:5]=='partn':
                    342:            nm=int(arg[5:])
                    343:            partners[nm]=argv[arg]
                    344:        elif arg[0:5]=='copyr':
                    345:            nm=int(arg[5:])
                    346:            copyrights[nm]=argv[arg]
                    347: 
                    348: 
                    349: 
                    350:    copyrightsList=[(medias[nm],partners[nm],copyrights[nm]) for nm in medias.keys()]
                    351:    for copyright in copyrightsList:
                    352:        
                    353:        if copyright[2]=='institution0000':
                    354:            copyrightsFinal.append((copyright[0],copyright[1],self.getPartnerCopyright(copyright[1],'')))
                    355:        else:
                    356:            if not copyright[0]=='':
                    357:                copyrightsFinal.append(copyright)
                    358:        
                    359:            
                    360:    return copyrightsFinal
                    361: 
                    362: #List of different types for the graphical linking viewer
                    363: viewClassificationListMaster=['view point','area']
                    364: 
                    365: 
                    366: def checkDiffs(self,metadict):
                    367:        """check differences"""
                    368: 
                    369:        
                    370: 
                    371:     
                    372:        def NoneToEmpty(obj):
                    373:            if obj:
                    374:                return obj
                    375:            else:
                    376:                return ""
                    377: 
                    378:        
                    379:        
                    380:        diffs={}
                    381:        
                    382:        tags=self.findTagsFromMapping(self.contentType)
                    383:        self.referencetypes=tags[2]
                    384:        self.fields=tags[3]
                    385:        
                    386:     
                    387:        for field in tags[1]:
                    388:            try:
                    389:                if (NoneToEmpty(self.getFieldValue(self.getFieldTag(tags,field)))==metadict[self.getFieldTag(tags,field)]):
                    390:                    diffs[self.getFieldTag(tags,field)]=1
                    391:                else:
                    392:                    
                    393:                    diffs[self.getFieldTag(tags,field)]=0
                    394:            except:
                    395:                diffs[self.getFieldTag(tags,field)]=0
                    396:                
                    397:        return diffs
                    398:     
                    399: 
                    400: 
                    401: 
                    402: def sendFile(self, filename, type):
                    403:     """sends an object or a local file (in the product) as response"""
                    404:     paths = filename.split('/')
                    405:     object = self
                    406:     # look for an object called filename
                    407:     for path in paths:
                    408:         if hasattr(object, path):
                    409:        object = getattr(object, path)
                    410:    else:
                    411:        object = None
                    412:        break
                    413:     if object:
                    414:    # if the object exists then send it
                    415:    return object.index_html(self.REQUEST.REQUEST, self.REQUEST.RESPONSE)
                    416:     else:
                    417:    # send a local file with the given content-type
                    418:    fn = os.path.join(package_home(globals()), filename)
                    419:    self.REQUEST.RESPONSE.setHeader("Content-Type", type)
                    420:    self.REQUEST.RESPONSE.write(file(fn).read())
                    421:     return
                    422: 
                    423: class BrowserCheck:
                    424:     """check the browsers request to find out the browser type"""
                    425:     
                    426:     def __init__(self, zope):
                    427:         """initialisiere"""
                    428:    self.ua = zope.REQUEST.get_header("HTTP_USER_AGENT")
                    429:    self.isN4 = (string.find(self.ua, 'Mozilla/4.') > -1) and (string.find(self.ua, 'MSIE') < 0)
                    430:    self.isIE = string.find(self.ua, 'MSIE') > -1
                    431:    self.nav = self.ua[string.find(self.ua, '('):]
                    432:    ie = string.split(self.nav, "; ")[1]
                    433:    if string.find(ie, "MSIE") > -1:
                    434:        self.versIE = string.split(ie, " ")[1]
                    435:    self.isMac = string.find(self.ua, 'Macintosh') > -1
                    436:    self.isWin = string.find(self.ua, 'Windows') > -1
                    437:    self.isIEWin = self.isIE and self.isWin
                    438:    self.isIEMac = self.isIE and self.isMac
                    439: 
                    440:        
                    441:        
                    442: def writeMetadata(url,metadict,project=None,startpage=None,xslt=None,thumbtemplate=None,topbar=None,digiLibTemplate=None,xmlfrag=None,digiliburlprefix=None):
                    443:    """Einlesen der Metadaten und und erstellen des geaenderten XML file"""
                    444: 
                    445:    def updateTextToolNode(tag,value):
                    446:        #print dom,tag,value
                    447:        metanode=dom.getElementsByTagName('texttool')[0]
                    448:        try:
                    449:            nodeOld=metanode.getElementsByTagName(tag)
                    450:        except:
                    451:            nodeOld=None
                    452:            
                    453:        if nodeOld:
                    454:            metanode.removeChild(nodeOld[0]).unlink()
                    455: 
                    456:        node=dom.createElement(tag)
                    457:        nodetext=dom.createTextNode(value)
                    458:        node.appendChild(nodetext)
                    459:        metanode.appendChild(node)
                    460: 
                    461:    if xmlfrag:
                    462:        geturl="""<?xml version="1.0" ?>
                    463:                            <resource type="MPIWG">
                    464:               <meta>
                    465:                <bib type="Book">
                    466:                        </bib>
                    467:                </meta>
                    468:                </resource>"""
                    469:        dom=xml.dom.minidom.parseString(geturl)
                    470:    else:
                    471:        try:
                    472:            geturl=""
                    473:            for line in ECHO_helpers.urlopen(url).readlines():
                    474:                geturl=geturl+line
                    475: 
                    476: 
                    477:        except:
                    478:            return (None,"Cannot open: "+url)
                    479: 
                    480:        try:
                    481:            dom=xml.dom.minidom.parseString(geturl)
                    482:        except:
                    483:            return (None,"Cannot parse: "+url+"<br>"+geturl)
                    484: 
                    485:    
                    486: 
                    487:    metanodes=dom.getElementsByTagName('bib')
                    488: 
                    489:    if not metanodes:
                    490:        metanodes=dom.getElementsByTagName('archimedes')
                    491: 
                    492:    metanode=metanodes[0]
                    493: 
                    494:    for metaData in metadict.keys():
                    495:        
                    496:        try:
                    497:            nodeOld=metanode.getElementsByTagName(metaData)
                    498:        except:
                    499:            nodeOld=None
                    500:            
                    501:        if nodeOld:
                    502:            metanode.removeChild(nodeOld[0]).unlink()
                    503:        else:
                    504:            # try also old writing rule - instead of _:
                    505:            try:
                    506:                nodeOld=metanode.getElementsByTagName(re.sub('_','-',metaData))
                    507:            except:
                    508:                nodeOld=None
                    509:                
                    510:            if nodeOld:
                    511:                metanode.removeChild(nodeOld[0]).unlink()
                    512: 
                    513:        metanodeneu=dom.createElement(metaData)
                    514:                 metanodetext=dom.createTextNode(metadict[metaData])
                    515:        #try:
                    516:            #metanodetext=dom.createTextNode(unicode(metadict[metaData],"utf-8"))
                    517:        #except:
                    518:            #metanodetext=dom.createTextNode(metadict[metaData].encode('utf-8'))
                    519:        metanodeneu.appendChild(metanodetext)
                    520:        metanode.appendChild(metanodeneu)
                    521: 
                    522: 
                    523:    
                    524:    
                    525:    
                    526:    if project:
                    527:        updateTextToolNode('project',project)
                    528: 
                    529:    if startpage:
                    530:        updateTextToolNode('startpage',startpage)
                    531: 
                    532:    if topbar:
                    533:        updateTextToolNode('toptemplate',topbar)
                    534: 
                    535:    if thumbtemplate:
                    536:        updateTextToolNode('thumbtemplate',thumbtemplate)
                    537: 
                    538:    if xslt:
                    539:        updateTextToolNode('xslt',xslt)
                    540: 
                    541:    
                    542:    if digiliburlprefix:
                    543:        updateTextToolNode('digiliburlprefix',digiliburlprefix)
                    544:    
                    545:         try:   
                    546:     return dom.toxml().encode('utf-8')
                    547:    except:
                    548:     return dom.toxml('utf-8')
                    549: 
                    550:    
                    551:    
                    552: def readMetadata(url):
                    553:     """Methode zum Auslesen der Metadateninformation zu einer Resource
                    554:     Vorerst noch Typ bib"""
                    555:     
                    556:     metadict={}
                    557:     try:
                    558:         geturl=""
                    559:         for line in ECHO_helpers.urlopen(url).readlines():
                    560:             geturl=geturl+line
                    561:         
                    562:         
                    563:     except:
                    564:         return (None,"Cannot open: "+url)
                    565: 
                    566:     try:
                    567:         dom=xml.dom.minidom.parseString(geturl)
                    568:     except:
                    569:         return (None,"Cannot parse: "+url+"<br>"+geturl)
                    570: 
                    571:     metanode=dom.getElementsByTagName('bib')
                    572:     metadict['bib_type']='Book'
                    573:     if len(metanode)==0:
                    574:         metanode=dom.getElementsByTagName('archimedes')
                    575:         metadict['bib_type']='Archimedes'
                    576:         
                    577:         
                    578:     if not len(metanode)==0:    
                    579:         metacontent=metanode[0].childNodes
                    580:     
                    581:         try:
                    582:             metadict['bib_type']=getText(dom.getElementsByTagName('bib')[0].attributes['type'].childNodes)
                    583:         except:
                    584:             """nothing"""
                    585:         
                    586:         for node in metacontent:
                    587:             try:
                    588:            #print urllib.unquote(getText(node.childNodes)),getText(node.childNodes)
                    589:            metadict[re.sub('-','_',node.tagName.lower())]=urllib.unquote(getText(node.childNodes))
                    590:             except:
                    591:                 """nothing"""
                    592: 
                    593: 
                    594:     return metadict,""
                    595:     

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>