view OSAS_metadata.py @ 8:4cd862bf37a3

more renovation
author casties
date Thu, 28 Jul 2011 14:54:54 +0200
parents 9f9d9be26e53
children 9a1e75e708e1
line wrap: on
line source

""" Classes for managing metadata"""

from OFS.SimpleItem import SimpleItem
from Globals import InitializeClass,package_home
from OFS.Folder import Folder
from AccessControl import ClassSecurityInfo
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
import os.path
import sys
import xml.dom.minidom
import xml.dom.pulldom
#TODO: get rid of this
from Products.OSA_system2 import OSAS_helpers
import logging

#ersetzt logging
def logger(txt,method,txt2):
    """logging"""
    logging.info(txt+ txt2)


import string
try:
    from xml.xpath import Evaluate
except:
    from Ft.Xml.XPath import Evaluate
import xmlrpclib

from types import *

class OSAS_MetadataMapping(SimpleItem):
    """Einfaches Mapping Object"""

    meta_type="OSAS_MetadataMapping__neu"

    def readFieldsFromParent(self):
        """read all elements from root"""
        
        return self.aq_parent.fieldList
    
    def __init__(self,id,title,arglist):
        """init
        @param id: id
        @param title: title fuer zope navigation
        @param arglist: dictionary mit Namen der zugelassenen generische Metadaten als key und Tripel  als Werte (human readable, tag version,explanation
        """
        self.id=id
        self.title=title
        for fieldName in arglist.keys():
            setattr(self,"md_"+fieldName,arglist[fieldName])
        
           
    manage_options = SimpleItem.manage_options+(
        {'label':'Main Config','action':'changeMetadataMappingForm'},
        )


    def showSetXML(self,RESPONSE=None):
        """prints out the mapping as XML"""
        ret="""<set name="%s">"""%self.title
        for fieldName in self.readFieldsFromParent():
            entry=getattr(self,"md_"+fieldName)
            if entry[2]=="": # no explanation of this field
                ret+="""<entry genericName="%s" tag="%s" label="%s"/>"""%(fieldName,entry[0],entry[1])
            else:
                ret+="""<entry genericName="%s" tag="%s" label="%s">%s</entry>"""%(fieldName,entry[0],entry[1],entry[2])
        ret+="</set>"

        if not RESPONSE:
            return ret
        else:
            self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml')
            return ret

    def getValue(self,fieldName):
        """get md value
        @param fieldName: Bezeichnung des gesuchten Metadatums
        @retunr: Value des Metadatums"""
        
        ret= getattr(self,"md_"+fieldName,(None,None,None,None,None))
        if len(ret)!= 4: # alte MD haben keine info ueber optional/required und listen werte
            ret=ret+("","")
        return ret
    

    def isEmptyValue(self,fieldName):
        """teste ob fielname in diesem Metadatenschema definiert ist"""
        field=getattr(self,"md_"+fieldName,'')
        if field[1]=='':
            return 0
        else:
            return 1
        
    def generateMappingHash(self):
        """erzeugen des dictionaries: generisches Feld -> Definition in diesem Schema"""
        hash={}
        for field in self.fieldList:
            hash[field]=getattr(self,"md_"+field,'')
        return hash

       
    
    def changeMetadataMappingForm(self):
        """change"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMetadataMapping.zpt')).__of__(self)
        return pt()
    
    def changeMetadataMapping(self,titleOfObject,RESPONSE=None):
        """change"""

        self.title=titleOfObject
        arglist=self.REQUEST.form
        
        for fieldName in self.readFieldsFromParent():
            setattr(self,"md_"+fieldName,(arglist[fieldName],arglist['label_'+fieldName],arglist['explanation_'+fieldName],arglist['status_'+fieldName],arglist['values_'+fieldName]))
            
            
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')

    manage_workspace=changeMetadataMappingForm    

def manage_addMetadataMappingForm(self):
    """interface for adding the OSAS_root"""
    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataMappingForm.zpt')).__of__(self)

    return pt()

def manage_addMetadataMapping(self,idOfObject,titleOfObject,RESPONSE=None):
    """add the OSAS_root"""
    
    argList={}
    for arg in self.fieldList:
        if not (arg in ['idOfObject','titleOfObject']):
            argList[arg]=(self.REQUEST.form[arg],self.REQUEST.form['label_'+arg],self.REQUEST.form['explanation_'+arg],self.REQUEST.form['status_'+arg],self.REQUEST.form['values_'+arg])
            
    newObj=OSAS_MetadataMapping(idOfObject,titleOfObject,argList)
    self._setObject(idOfObject,newObj)
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')

   

class OSAS_Metadata(Folder):
    """Foldertype enthaelt methoden zur Halbautomatischen Erstellung von Metadatenfiles"""
    security=ClassSecurityInfo()
    
    def __init__(self,id,shortDescription,description,fields):
        """initialize a new instance"""
        self.id = id
        self.shortDescription =shortDescription #label fuer link auf add page
        self.description=description #description of the method for link page
        self.fieldList=fields.split(",")[0:]
        
    meta_type='OSAS_Metadata__neu'

    manage_options = Folder.manage_options+(
        {'label':'Main Config','action':'changeMetadataForm'},
        {'label':'Import XML Schema','action':'importXMLSchemaForm'},
        {'label':'Select Fields for Display','action':'indicateDisplayFieldsForm'},
        )

    def showGenericXML(self,RESPONSE=None):
        """show generic fields as XML"""
        ret="""<set name="%s">"""%"generic"
        for field in self.fieldList:
            ret+="""<entry genericName="%s"/>"""%field

        ret+="</set>"
        
        if not RESPONSE:
            return ret
        else:
            self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml')
            return ret
    
  
    def showOverviewXML(self,RESPONSE=None,wrapped=False):
        """gives an overview over the Metadata stored in this folder"""
        ret=""
        if wrapped:
            ret+="""<metadataExport>"""
        ret+="""<metadata name="%s">"""%self.getId()
        ret+=self.showGenericXML()
        for entry in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
            ret+=entry[1].showSetXML()

        for entry in self.ZopeFind(self,obj_metatypes=['OSAS_Metadata__neu']):
            ret+=entry[1].showOverviewXML()

        ret+="</metadata>"

        if wrapped:
            ret+="""</metadataExport>"""
        if not RESPONSE:
            return ret
        else:
            RESPONSE.setHeader('Content-Type','text/xml')
            return ret
        
    def generateMappingList(self):
        """Erzeuge Mapping"""
        mapping={}

        for dict in self.__dict__:
            #print dict
            obj=getattr(self,dict)
            if hasattr(obj,'meta_type'):
                logging.debug("generateMappungList read type:"+repr(obj.meta_type))
                if ((obj.meta_type=="OSAS_MetadataMapping__neu") or (obj.meta_type=="MetadataMapping")): #metadatamapping is the newer type
                    logging.debug("generateMappungListadded:"+repr(obj.getId()))
                    mapping[obj.getId()]=obj.generateMappingHash()
        
        return mapping
    
    def generateMappingForType(self,type,clean="yes"):
        """erzeuge spezifisches Mapping"""
        
        hash=self.generateMappingList()
        logging.debug("generateMappingForType:"+type)
        for key in hash.keys():
            logging.debug("generateMappingForType comparing:"+key.lower()+type.lower())
            if (key.lower() == type.lower()):
                if clean=="yes":
                    temp={}
                    for x in hash[key].keys():
                        if not hash[key][x]=="":
                            temp[x]=hash[key][x]
                    return temp
                else:
    
                    return hash[key]
            
        return {}

    def getFieldList(self):
        """erzeuge string aus fields"""
        try:
            return string.join(self.fieldList,",")
        except:
            return ""
        
    security.declarePublic('getFields')
    def getFields(self):
        """ausgabe der Felder"""
        return self.fieldList

    def getTypeTitle(self,id):
        """Title von ID"""
        try:
            obj=getattr(self,id)
            return obj.title
        except:
            return id

    def getType(self,type):
        """gib metadataobject type zurueck"""

        for obj in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
            if obj[0]==type:
                return obj
        return (self.id,self)

        
        
    def getStoredTypes(self):
        """Gebe gespeicherte typen zurueck"""
        
        types=[]

        for obj in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
	    if obj[1].title=="":
		title=obj[1].id
	    else:
		title=obj[1].title
	    types.append((obj[1].id, title, obj[1]))

        return types

    def indicateDisplayFieldsForm(self):
        """form zur Makierung der Felder die in der Browserumgebung angezeigt werden"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','indicateDisplayFieldsForm.zpt')).__of__(self)
        return pt()

    def indicateDisplayFields(self,displayFields,RESPONSE=None):
        """set Displayfields
        @param displayFields: Liste von Felder die im Browserenvironment angezeigt werden
        """
        self.displayFields=OSAS_helpers.toList(displayFields)
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')

    def getDisplayFieldsAsStr(self,indexMeta):
        ret=[]
        try:
         if indexMeta and not (indexMeta==""):
            dom=xml.dom.pulldom.parseString(indexMeta)

            for (event,node) in dom:

                if event == xml.dom.pulldom.START_ELEMENT and node.tagName=="bib":
                    dom.expandNode(node)

                    try:
                        type=node.getAttribute('type')
                        mapping=getattr(self,type).generateMappingHash()
                    except:
                        type='generic'
                        mapping=getattr(self,type).generateMappingHash()

                    for field in self.displayFields:
                        try:
                            ret.append(OSAS_helpers.getText(node.getElementsByTagName(mapping[field][0])[0].childNodes))
                        except:
                            """nothing"""

                    return "; ".join(ret)
         else:
            return ""
        except:
            return ""
    def getDisplayFieldsAsStrOLD(self,indexMeta):
        """Gebe display fields als string zurueck
        @param path: Pfad zum Object
        """
        ret=[]
        try:
            dom=xml.dom.minidom.parseString(indexMeta)
        except:
            logger("OSAS_metadata (getDisplayFieldsAsStr)",logging.INFO,"Cannot parse: %s"%indexMeta)
        try:
            bib = dom.getElementsByTagName("meta")[0].getElementsByTagName("bib")[0]
        except:
            return ""
        try:
            type=bib.getAttribute('type')
            mapping=getattr(self,type).generateMappingHash()
        except:
            type='generic'
            mapping=getattr(self,type).generateMappingHash()

        for field in self.displayFields:
            try:
                ret.append(OSAS_helpers.getText(bib.getElementsByTagName(mapping[field][0])[0].childNodes))
            except:
                """nothing"""
                
        return "; ".join(ret)

    security.declarePublic('changeMetadataForm')
    def changeMetadataForm(self):
        """Main configuration"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMetadata.zpt')).__of__(self)
        return pt()
    
    security.declarePublic('changeMetadata')
    def changeMetadata(self,shortDescription,description,fields,RESPONSE=None):
        """Change Metadata"""
        self.shortDescription=shortDescription
        self.description=description
        self.fieldList=fields.split(",")[0:]
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')

    security.declarePublic('index_html')

    def importXMLSchemaForm(self):
        """form"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importXMLSchemaForm.zpt')).__of__(self)
        return pt()

    
    def importXMLSchema(self,file,RESPONSE=None):
       """import xmlschema, Metadatenschema wird eingelesen und entsprechende Metadatenmappings angelegt."""

       dom=xml.dom.minidom.parse(file)
       sets=dom.getElementsByTagName('set')
       #erster schritt: anlegen der fieldlist
       for set in sets:
           if set.getAttribute('name')=='generic':
               list=[]
               for entry in set.getElementsByTagName('entry'):
                   list.append(entry.getAttribute('genericName'))
               self.fieldList=list[0:]

       #zweiter schritt: anlegen der mapping
       for set in sets:
           id=set.getAttribute('name').encode('utf-8')
           list=[]
           argList={}
           for entry in set.getElementsByTagName('entry'):
               genericName=entry.getAttribute('genericName')
               tag=entry.getAttribute('tag')
               label=entry.getAttribute('label')
               description=OSAS_helpers.getText(entry.childNodes)
               argList[genericName]=(tag,label,description)
           self._setObject(id,OSAS_MetadataMapping(id,id,argList))
           if RESPONSE:
               RESPONSE.write("Wrote: %s"%id)


    def createMetadataFragment(self,type,path,prefix="",presets={}):
        """fragment"""
        self.REQUEST.SESSION['MDF_type']=type
        self.REQUEST.SESSION['MDF_path']=path
        self.REQUEST.SESSION['MDF_prefix']=prefix
        self.REQUEST.SESSION['MDF_presets']=presets

        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm_fragment.zpt')).__of__(self)
        return pt()

    def createMetadataForm(self,type="",path=""):
        """createMetadataForm"""
        self.REQUEST.SESSION['MDF_type']=type
        self.REQUEST.SESSION['MDF_path']=path

        
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm_template.zpt')).__of__(self)
        return pt()

    def readMetadata(self,MDF_path,MDF_type,MDF_prefix="",MDF_xpathStart="", MDF_addPath=None,MDF_identifyFields=None,newdoc=None,actualNode=None):

        if type(MDF_path)==ListType:
                MDF_path=MDF_path[0]

        indexFile=os.path.join(MDF_path,'index.meta')

        server=xmlrpclib.Server(self.serverUrl)
        
        documentStr=server.getFile(indexFile)
        
        if documentStr:
            newdoc=xml.dom.minidom.parseString(documentStr)
            dom=newdoc.documentElement
            actualNode=dom
        else:
            return {}

        if self.containerTag=="":
            containerTag="doc"
        else:
            containerTag=self.containerTag
            
        if MDF_xpathStart=="":
            dom=newdoc.documentElement
            actualNode=dom
        else:
            #try to find xpath
            if MDF_identifyFields:
                query=[]
                for field in MDF_identifyFields.keys():

                    query.append("""(%s="%s")"""%(field,MDF_identifyFields[field]))
                querystr=" and ".join(query)
                xpathStr=MDF_xpathStart+"[%s]"%querystr
                
            else:
                xpathStr=MDF_xpathStart


            xpathNodes=Evaluate(xpathStr,actualNode)
            

            if len(xpathNodes)>0:
                actualNode=xpathNodes[0]
            else:
                return {}

        ret={}
        for node in actualNode.childNodes:
            name=node.tagName
            text=OSAS_helpers.getText(node.childNodes)
            ret[name]=text

        return ret
        
    def writeMetadata(self,MDF_path,MDF_type,form,MDF_prefix="",MDF_xpathStart="", MDF_addPath=None,MDF_identifyFields=None,newdoc=None,actualNode=None):
        """writeMetadata"""
        #MDF_path="/tmp/index.meta"
        if type(MDF_path)==ListType:
                MDF_path=MDF_path[0]


        indexFile=os.path.join(MDF_path,'index.meta')
        
        server=xmlrpclib.Server(self.serverUrl)
        if newdoc:
            if not actualNode: actualNode=newdoc
            dom=newdoc
        else:
            documentStr=server.getFile(indexFile)

            if documentStr:

                newdoc=xml.dom.minidom.parseString(documentStr)
                dom=newdoc.documentElement
                actualNode=dom


            else:

                impl=xml.dom.minidom.getDOMImplementation()
                newdoc=None

        
        if self.containerTag=="":
            containerTag="doc"
        else:
            containerTag=self.containerTag

        create=None
        if MDF_xpathStart=="":
            if not newdoc:
                newdoc=impl.createDocument(None,containerTag,None)
            dom=newdoc.documentElement
            actualNode=dom
        else:

            #try to find xpath
            if MDF_identifyFields:
                query=[]
                for field in MDF_identifyFields:

                    query.append("""(%s="%s")"""%(field,form[MDF_prefix+"MD_"+field]))
                querystr=" and ".join(query)
                xpathStr=MDF_xpathStart+"[%s]"%querystr
                
            else:
                xpathStr=MDF_xpathStart


            xpathNodes=Evaluate(xpathStr,actualNode)
            



            if len(xpathNodes)>0:
                actualNode=xpathNodes[0]

            else:
                #existiert nicht dann neue erzeugen

                if len(Evaluate(MDF_xpathStart,dom))>0:

                    create=True
                
                splitted=MDF_xpathStart.split("/")
                base=""
                for element in splitted:

                    if not (element=="") and not (element==containerTag):
                        base="/".join([base,element])
                        
                        if not newdoc:
                            newdoc=impl.createDocument(None,element,None)
                            actualNode=newdoc.documentElement
                            dom=actualNode
                        else:
                            changed=None

                            if not (MDF_addPath==base):


                                for childNode in actualNode.childNodes:
                                    if getattr(childNode,'tagName','')==element:
                                        actualNode=childNode
                                        changed=1

                                        if (os.path.normpath("/".join(["",containerTag,base]))==MDF_xpathStart) and create:
                                            actualNode=actualNode.parentNode
                                            changed=None

                            if not changed:
                                namenode=newdoc.createElement(element)

                                actualNode.appendChild(namenode)
                                actualNode=namenode


            
        
        for name in self.REQUEST.form.keys():
            length=len(MDF_prefix)
            if MDF_type and not (MDF_type == ""):
                actualNode.setAttribute("type",MDF_type)
            if name[0:3+length]==MDF_prefix+"MD_":
                tagName=name[3+length:]

                #CHECK if element exists
                for childNode in actualNode.childNodes:
                    if getattr(childNode,'tagName','')==tagName:
                        actualNode.removeChild(childNode).unlink()
                
                namenode=newdoc.createElement(tagName)
                namenodetext=newdoc.createTextNode(self.REQUEST.form[name])
                namenode.appendChild(namenodetext)
                actualNode.appendChild(namenode)
                
        ret=newdoc.toxml(encoding='utf-8')
        zLOG.LOG("OSAS_metadata (writeMetadata)",zLOG.INFO,"write: %s"%ret)


        server.writeMetaDataFile(indexFile,ret)


        return newdoc,actualNode

    def writeMetadataFile(self,MDF_path,MDF_type,MDF_xpathStart="",newdoc=None,actualNode=None):
        """writeMetaFile"""

        return self.writeMetadata(MDF_path,MDF_type,self.REQUEST.form,MDF_xpathStart=MDF_xpathStart,newdoc=newdoc,actualNode=actualNode)

    
    def isEmptyValue(self,fieldName):
        """im generischen fall stets falsch"""
        return 1

    def getValue(self,fieldName):
        """im generischen fall gleich fieldname"""
        return fieldName,fieldName,"","",""

    def getList(self,list):
        """return list"""

        if list=="":
            return None
        listsplit=[i.rstrip() for i in list.split("\n")]
        return listsplit

    def showHelp(self,refType,genericTag):
        """helptext"""
        for reference in self.ZopeFind(self):
            if reference[1].title==refType:
                text=getattr(reference[1],'md_'+genericTag)[2]
                return text
        return "NO EXPLANATION"

    def showHelpTag(self,url,reftype,item):
        """gen javascript for showhelp"""
        url2=url+'/showHelp?refType=%s&genericTag=%s'%(reftype,item)
        ret="""javascript:wd=window.open(\'%s\',\'Help\',\'width=300,height=250\');void(\'\');wd.focus();"""%url2
        return ret

        
def manage_addMetadataForm(self):
    """interface for adding the OSAS_add_Metadata"""
    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm.zpt')).__of__(self)
    return pt()

def manage_addMetadata(self,id,shortDescription,description,fields,RESPONSE=None):
    """add the OSAS_root"""
    newObj=OSAS_Metadata(id,shortDescription,description,fields)
    self.Destination()._setObject(id,newObj)
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')