1: """ Classes for managing metadata"""
2:
3: from OFS.SimpleItem import SimpleItem
4: from Globals import InitializeClass,package_home
5: from OFS.Folder import Folder
6: from AccessControl import ClassSecurityInfo
7: from Products.PageTemplates.PageTemplateFile import PageTemplateFile
8: import os.path
9: import sys
10: import xml.dom.minidom
11: import xml.dom.pulldom
12: import OSAS_helpers
13: import logging
14:
15: #ersetzt logging
16: def logger(txt,method,txt2):
17: """logging"""
18: logging.info(txt+ txt2)
19:
20:
21: import string
22: try:
23: from xml.xpath import Evaluate
24: except:
25: from Ft.Xml.XPath import Evaluate
26: import xmlrpclib
27:
28: from types import *
29:
30: class OSAS_MetadataMapping(SimpleItem):
31: """Einfaches Mapping Object"""
32:
33: meta_type="OSAS_MetadataMapping__neu"
34:
35: def readFieldsFromParent(self):
36: """read all elements from root"""
37:
38: return self.aq_parent.fieldList
39:
40: def __init__(self,id,title,arglist):
41: """init
42: @param id: id
43: @param title: title fuer zope navigation
44: @param arglist: dictionary mit Namen der zugelassenen generische Metadaten als key und Tripel als Werte (human readable, tag version,explanation
45: """
46: self.id=id
47: self.title=title
48: for fieldName in arglist.keys():
49: setattr(self,"md_"+fieldName,arglist[fieldName])
50:
51:
52: manage_options = SimpleItem.manage_options+(
53: {'label':'Main Config','action':'changeMetadataMappingForm'},
54: )
55:
56:
57: def showSetXML(self,RESPONSE=None):
58: """prints out the mapping as XML"""
59: ret="""<set name="%s">"""%self.title
60: for fieldName in self.readFieldsFromParent():
61: entry=getattr(self,"md_"+fieldName)
62: if entry[2]=="": # no explanation of this field
63: ret+="""<entry genericName="%s" tag="%s" label="%s"/>"""%(fieldName,entry[0],entry[1])
64: else:
65: ret+="""<entry genericName="%s" tag="%s" label="%s">%s</entry>"""%(fieldName,entry[0],entry[1],entry[2])
66: ret+="</set>"
67:
68: if not RESPONSE:
69: return ret
70: else:
71: self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml')
72: return ret
73:
74: def getValue(self,fieldName):
75: """get md value
76: @param fieldName: Bezeichnung des gesuchten Metadatums
77: @retunr: Value des Metadatums"""
78:
79: ret= getattr(self,"md_"+fieldName,(None,None,None,None,None))
80: if len(ret)!= 4: # alte MD haben keine info ueber optional/required und listen werte
81: ret=ret+("","")
82: return ret
83:
84:
85: def isEmptyValue(self,fieldName):
86: """teste ob fielname in diesem Metadatenschema definiert ist"""
87: field=getattr(self,"md_"+fieldName,'')
88: if field[1]=='':
89: return 0
90: else:
91: return 1
92:
93: def generateMappingHash(self):
94: """erzeugen des dictionaries: generisches Feld -> Definition in diesem Schema"""
95: hash={}
96: for field in self.fieldList:
97: hash[field]=getattr(self,"md_"+field)
98: return hash
99:
100:
101:
102: def changeMetadataMappingForm(self):
103: """change"""
104: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMetadataMapping.zpt')).__of__(self)
105: return pt()
106:
107: def changeMetadataMapping(self,titleOfObject,RESPONSE=None):
108: """change"""
109:
110: self.title=titleOfObject
111: arglist=self.REQUEST.form
112:
113: for fieldName in self.readFieldsFromParent():
114: setattr(self,"md_"+fieldName,(arglist[fieldName],arglist['label_'+fieldName],arglist['explanation_'+fieldName],arglist['status_'+fieldName],arglist['values_'+fieldName]))
115:
116:
117: if RESPONSE is not None:
118: RESPONSE.redirect('manage_main')
119:
120: manage_workspace=changeMetadataMappingForm
121:
122: def manage_addMetadataMappingForm(self):
123: """interface for adding the OSAS_root"""
124: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataMappingForm.zpt')).__of__(self)
125:
126: return pt()
127:
128: def manage_addMetadataMapping(self,idOfObject,titleOfObject,RESPONSE=None):
129: """add the OSAS_root"""
130:
131: argList={}
132: for arg in self.fieldList:
133: if not (arg in ['idOfObject','titleOfObject']):
134: 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])
135:
136: newObj=OSAS_MetadataMapping(idOfObject,titleOfObject,argList)
137: self._setObject(idOfObject,newObj)
138: if RESPONSE is not None:
139: RESPONSE.redirect('manage_main')
140:
141:
142:
143: class OSAS_Metadata(Folder):
144: """Foldertype enthaelt methoden zur Halbautomatischen Erstellung von Metadatenfiles"""
145: security=ClassSecurityInfo()
146:
147: def __init__(self,id,shortDescription,description,fields):
148: """initialize a new instance"""
149: self.id = id
150: self.shortDescription =shortDescription #label fuer link auf add page
151: self.description=description #description of the method for link page
152: self.fieldList=fields.split(",")[0:]
153:
154: meta_type='OSAS_Metadata__neu'
155:
156: manage_options = Folder.manage_options+(
157: {'label':'Main Config','action':'changeMetadataForm'},
158: {'label':'Import XML Schema','action':'importXMLSchemaForm'},
159: {'label':'Select Fields for Display','action':'indicateDisplayFieldsForm'},
160: )
161:
162: def showGenericXML(self,RESPONSE=None):
163: """show generic fields as XML"""
164: ret="""<set name="%s">"""%"generic"
165: for field in self.fieldList:
166: ret+="""<entry genericName="%s"/>"""%field
167:
168: ret+="</set>"
169:
170: if not RESPONSE:
171: return ret
172: else:
173: self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml')
174: return ret
175:
176:
177: def showOverviewXML(self,RESPONSE=None,wrapped=False):
178: """gives an overview over the Metadata stored in this folder"""
179: ret=""
180: if wrapped:
181: ret+="""<metadataExport>"""
182: ret+="""<metadata name="%s">"""%self.getId()
183: ret+=self.showGenericXML()
184: for entry in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
185: ret+=entry[1].showSetXML()
186:
187: for entry in self.ZopeFind(self,obj_metatypes=['OSAS_Metadata__neu']):
188: ret+=entry[1].showOverviewXML()
189:
190: ret+="</metadata>"
191:
192: if wrapped:
193: ret+="""</metadataExport>"""
194: if not RESPONSE:
195: return ret
196: else:
197: RESPONSE.setHeader('Content-Type','text/xml')
198: return ret
199:
200: def generateMappingList(self):
201: """Erzeuge Mapping"""
202: mapping={}
203:
204: for dict in self.__dict__:
205: #print dict
206: obj=getattr(self,dict)
207: if hasattr(obj,'meta_type'):
208: logging.debug("generateMappungList read type:"+repr(obj.meta_type))
209: if ((obj.meta_type=="OSAS_MetadataMapping__neu") or (obj.meta_type=="MetadataMapping")): #metadatamapping is the newer type
210: logging.debug("generateMappungListadded:"+repr(obj.getId()))
211: mapping[obj.getId()]=obj.generateMappingHash()
212:
213: return mapping
214:
215: def generateMappingForType(self,type,clean="yes"):
216: """erzeuge spezifisches Mapping"""
217:
218: hash=self.generateMappingList()
219: logging.debug("generateMappingForType:"+type)
220: for key in hash.keys():
221: logging.debug("generateMappingForType comparing:"+key.lower()+type.lower())
222: if (key.lower() == type.lower()):
223: if clean=="yes":
224: temp={}
225: for x in hash[key].keys():
226: if not hash[key][x]=="":
227: temp[x]=hash[key][x]
228: return temp
229: else:
230:
231: return hash[key]
232:
233: return {}
234:
235: def getFieldList(self):
236: """erzeuge string aus fields"""
237: try:
238: return string.join(self.fieldList,",")
239: except:
240: return ""
241:
242: security.declarePublic('getFields')
243: def getFields(self):
244: """ausgabe der Felder"""
245: return self.fieldList
246:
247: def getTypeTitle(self,id):
248: """Title von ID"""
249: try:
250: obj=getattr(self,id)
251: return obj.title
252: except:
253: return id
254:
255: def getType(self,type):
256: """gib metadataobject type zurueck"""
257:
258: for obj in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
259: if obj[0]==type:
260: return obj
261: return (self.id,self)
262:
263:
264:
265: def getStoredTypes(self):
266: """Gebe gespeicherte typen zurueck"""
267:
268: types=[]
269:
270: for obj in self.ZopeFind(self,obj_metatypes=['OSAS_MetadataMapping__neu']):
271: if obj[1].title=="":
272: title=obj[1].id
273: else:
274: title=obj[1].title
275: types.append((obj[1].id, title, obj[1]))
276:
277: return types
278:
279: def indicateDisplayFieldsForm(self):
280: """form zur Makierung der Felder die in der Browserumgebung angezeigt werden"""
281: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','indicateDisplayFieldsForm.zpt')).__of__(self)
282: return pt()
283:
284: def indicateDisplayFields(self,displayFields,RESPONSE=None):
285: """set Displayfields
286: @param displayFields: Liste von Felder die im Browserenvironment angezeigt werden
287: """
288: self.displayFields=OSAS_helpers.toList(displayFields)
289: if RESPONSE is not None:
290: RESPONSE.redirect('manage_main')
291:
292: def getDisplayFieldsAsStr(self,indexMeta):
293: ret=[]
294: try:
295: if indexMeta and not (indexMeta==""):
296: dom=xml.dom.pulldom.parseString(indexMeta)
297:
298: for (event,node) in dom:
299:
300: if event == xml.dom.pulldom.START_ELEMENT and node.tagName=="bib":
301: dom.expandNode(node)
302:
303: try:
304: type=node.getAttribute('type')
305: mapping=getattr(self,type).generateMappingHash()
306: except:
307: type='generic'
308: mapping=getattr(self,type).generateMappingHash()
309:
310: for field in self.displayFields:
311: try:
312: ret.append(OSAS_helpers.getText(node.getElementsByTagName(mapping[field][0])[0].childNodes))
313: except:
314: """nothing"""
315:
316: return "; ".join(ret)
317: else:
318: return ""
319: except:
320: return ""
321: def getDisplayFieldsAsStrOLD(self,indexMeta):
322: """Gebe display fields als string zurueck
323: @param path: Pfad zum Object
324: """
325: ret=[]
326: try:
327: dom=xml.dom.minidom.parseString(indexMeta)
328: except:
329: logger("OSAS_metadata (getDisplayFieldsAsStr)",logging.INFO,"Cannot parse: %s"%indexMeta)
330: try:
331: bib = dom.getElementsByTagName("meta")[0].getElementsByTagName("bib")[0]
332: except:
333: return ""
334: try:
335: type=bib.getAttribute('type')
336: mapping=getattr(self,type).generateMappingHash()
337: except:
338: type='generic'
339: mapping=getattr(self,type).generateMappingHash()
340:
341: for field in self.displayFields:
342: try:
343: ret.append(OSAS_helpers.getText(bib.getElementsByTagName(mapping[field][0])[0].childNodes))
344: except:
345: """nothing"""
346:
347: return "; ".join(ret)
348:
349: security.declarePublic('changeMetadataForm')
350: def changeMetadataForm(self):
351: """Main configuration"""
352: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMetadata.zpt')).__of__(self)
353: return pt()
354:
355: security.declarePublic('changeMetadata')
356: def changeMetadata(self,shortDescription,description,fields,RESPONSE=None):
357: """Change Metadata"""
358: self.shortDescription=shortDescription
359: self.description=description
360: self.fieldList=fields.split(",")[0:]
361: if RESPONSE is not None:
362: RESPONSE.redirect('manage_main')
363:
364: security.declarePublic('index_html')
365:
366: def importXMLSchemaForm(self):
367: """form"""
368: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','importXMLSchemaForm.zpt')).__of__(self)
369: return pt()
370:
371:
372: def importXMLSchema(self,file,RESPONSE=None):
373: """import xmlschema, Metadatenschema wird eingelesen und entsprechende Metadatenmappings angelegt."""
374:
375: dom=xml.dom.minidom.parse(file)
376: sets=dom.getElementsByTagName('set')
377: #erster schritt: anlegen der fieldlist
378: for set in sets:
379: if set.getAttribute('name')=='generic':
380: list=[]
381: for entry in set.getElementsByTagName('entry'):
382: list.append(entry.getAttribute('genericName'))
383: self.fieldList=list[0:]
384:
385: #zweiter schritt: anlegen der mapping
386: for set in sets:
387: id=set.getAttribute('name').encode('utf-8')
388: list=[]
389: argList={}
390: for entry in set.getElementsByTagName('entry'):
391: genericName=entry.getAttribute('genericName')
392: tag=entry.getAttribute('tag')
393: label=entry.getAttribute('label')
394: description=OSAS_helpers.getText(entry.childNodes)
395: argList[genericName]=(tag,label,description)
396: self._setObject(id,OSAS_MetadataMapping(id,id,argList))
397: if RESPONSE:
398: RESPONSE.write("Wrote: %s"%id)
399:
400:
401: def createMetadataFragment(self,type,path,prefix="",presets={}):
402: """fragment"""
403: self.REQUEST.SESSION['MDF_type']=type
404: self.REQUEST.SESSION['MDF_path']=path
405: self.REQUEST.SESSION['MDF_prefix']=prefix
406: self.REQUEST.SESSION['MDF_presets']=presets
407:
408: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm_fragment.zpt')).__of__(self)
409: return pt()
410:
411: def createMetadataForm(self,type="",path=""):
412: """createMetadataForm"""
413: self.REQUEST.SESSION['MDF_type']=type
414: self.REQUEST.SESSION['MDF_path']=path
415:
416:
417: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm_template.zpt')).__of__(self)
418: return pt()
419:
420: def readMetadata(self,MDF_path,MDF_type,MDF_prefix="",MDF_xpathStart="", MDF_addPath=None,MDF_identifyFields=None,newdoc=None,actualNode=None):
421:
422: if type(MDF_path)==ListType:
423: MDF_path=MDF_path[0]
424:
425: indexFile=os.path.join(MDF_path,'index.meta')
426:
427: server=xmlrpclib.Server(self.serverUrl)
428:
429: documentStr=server.getFile(indexFile)
430:
431: if documentStr:
432: newdoc=xml.dom.minidom.parseString(documentStr)
433: dom=newdoc.documentElement
434: actualNode=dom
435: else:
436: return {}
437:
438: if self.containerTag=="":
439: containerTag="doc"
440: else:
441: containerTag=self.containerTag
442:
443: if MDF_xpathStart=="":
444: dom=newdoc.documentElement
445: actualNode=dom
446: else:
447: #try to find xpath
448: if MDF_identifyFields:
449: query=[]
450: for field in MDF_identifyFields.keys():
451:
452: query.append("""(%s="%s")"""%(field,MDF_identifyFields[field]))
453: querystr=" and ".join(query)
454: xpathStr=MDF_xpathStart+"[%s]"%querystr
455:
456: else:
457: xpathStr=MDF_xpathStart
458:
459:
460: xpathNodes=Evaluate(xpathStr,actualNode)
461:
462:
463: if len(xpathNodes)>0:
464: actualNode=xpathNodes[0]
465: else:
466: return {}
467:
468: ret={}
469: for node in actualNode.childNodes:
470: name=node.tagName
471: text=OSAS_helpers.getText(node.childNodes)
472: ret[name]=text
473:
474: return ret
475:
476: def writeMetadata(self,MDF_path,MDF_type,form,MDF_prefix="",MDF_xpathStart="", MDF_addPath=None,MDF_identifyFields=None,newdoc=None,actualNode=None):
477: """writeMetadata"""
478: #MDF_path="/tmp/index.meta"
479: if type(MDF_path)==ListType:
480: MDF_path=MDF_path[0]
481:
482:
483: indexFile=os.path.join(MDF_path,'index.meta')
484:
485: server=xmlrpclib.Server(self.serverUrl)
486: if newdoc:
487: if not actualNode: actualNode=newdoc
488: dom=newdoc
489: else:
490: documentStr=server.getFile(indexFile)
491:
492: if documentStr:
493:
494: newdoc=xml.dom.minidom.parseString(documentStr)
495: dom=newdoc.documentElement
496: actualNode=dom
497:
498:
499: else:
500:
501: impl=xml.dom.minidom.getDOMImplementation()
502: newdoc=None
503:
504:
505: if self.containerTag=="":
506: containerTag="doc"
507: else:
508: containerTag=self.containerTag
509:
510: create=None
511: if MDF_xpathStart=="":
512: if not newdoc:
513: newdoc=impl.createDocument(None,containerTag,None)
514: dom=newdoc.documentElement
515: actualNode=dom
516: else:
517:
518: #try to find xpath
519: if MDF_identifyFields:
520: query=[]
521: for field in MDF_identifyFields:
522:
523: query.append("""(%s="%s")"""%(field,form[MDF_prefix+"MD_"+field]))
524: querystr=" and ".join(query)
525: xpathStr=MDF_xpathStart+"[%s]"%querystr
526:
527: else:
528: xpathStr=MDF_xpathStart
529:
530:
531: xpathNodes=Evaluate(xpathStr,actualNode)
532:
533:
534:
535:
536: if len(xpathNodes)>0:
537: actualNode=xpathNodes[0]
538:
539: else:
540: #existiert nicht dann neue erzeugen
541:
542: if len(Evaluate(MDF_xpathStart,dom))>0:
543:
544: create=True
545:
546: splitted=MDF_xpathStart.split("/")
547: base=""
548: for element in splitted:
549:
550: if not (element=="") and not (element==containerTag):
551: base="/".join([base,element])
552:
553: if not newdoc:
554: newdoc=impl.createDocument(None,element,None)
555: actualNode=newdoc.documentElement
556: dom=actualNode
557: else:
558: changed=None
559:
560: if not (MDF_addPath==base):
561:
562:
563: for childNode in actualNode.childNodes:
564: if getattr(childNode,'tagName','')==element:
565: actualNode=childNode
566: changed=1
567:
568: if (os.path.normpath("/".join(["",containerTag,base]))==MDF_xpathStart) and create:
569: actualNode=actualNode.parentNode
570: changed=None
571:
572: if not changed:
573: namenode=newdoc.createElement(element)
574:
575: actualNode.appendChild(namenode)
576: actualNode=namenode
577:
578:
579:
580:
581: for name in self.REQUEST.form.keys():
582: length=len(MDF_prefix)
583: if MDF_type and not (MDF_type == ""):
584: actualNode.setAttribute("type",MDF_type)
585: if name[0:3+length]==MDF_prefix+"MD_":
586: tagName=name[3+length:]
587:
588: #CHECK if element exists
589: for childNode in actualNode.childNodes:
590: if getattr(childNode,'tagName','')==tagName:
591: actualNode.removeChild(childNode).unlink()
592:
593: namenode=newdoc.createElement(tagName)
594: namenodetext=newdoc.createTextNode(self.REQUEST.form[name])
595: namenode.appendChild(namenodetext)
596: actualNode.appendChild(namenode)
597:
598: ret=newdoc.toxml(encoding='utf-8')
599: zLOG.LOG("OSAS_metadata (writeMetadata)",zLOG.INFO,"write: %s"%ret)
600:
601:
602: server.writeMetaDataFile(indexFile,ret)
603:
604:
605: return newdoc,actualNode
606:
607: def writeMetadataFile(self,MDF_path,MDF_type,MDF_xpathStart="",newdoc=None,actualNode=None):
608: """writeMetaFile"""
609:
610: return self.writeMetadata(MDF_path,MDF_type,self.REQUEST.form,MDF_xpathStart=MDF_xpathStart,newdoc=newdoc,actualNode=actualNode)
611:
612:
613: def isEmptyValue(self,fieldName):
614: """im generischen fall stets falsch"""
615: return 1
616:
617: def getValue(self,fieldName):
618: """im generischen fall gleich fieldname"""
619: return fieldName,fieldName,"","",""
620:
621: def getList(self,list):
622: """return list"""
623:
624: if list=="":
625: return None
626: listsplit=[i.rstrip() for i in list.split("\n")]
627: return listsplit
628:
629: def showHelp(self,refType,genericTag):
630: """helptext"""
631: for reference in self.ZopeFind(self):
632: if reference[1].title==refType:
633: text=getattr(reference[1],'md_'+genericTag)[2]
634: return text
635: return "NO EXPLANATION"
636:
637: def showHelpTag(self,url,reftype,item):
638: """gen javascript for showhelp"""
639: url2=url+'/showHelp?refType=%s&genericTag=%s'%(reftype,item)
640: ret="""javascript:wd=window.open(\'%s\',\'Help\',\'width=300,height=250\');void(\'\');wd.focus();"""%url2
641: return ret
642:
643:
644: def manage_addMetadataForm(self):
645: """interface for adding the OSAS_add_Metadata"""
646: pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMetadataForm.zpt')).__of__(self)
647: return pt()
648:
649: def manage_addMetadata(self,id,shortDescription,description,fields,RESPONSE=None):
650: """add the OSAS_root"""
651: newObj=OSAS_Metadata(id,shortDescription,description,fields)
652: self.Destination()._setObject(id,newObj)
653: if RESPONSE is not None:
654: RESPONSE.redirect('manage_main')
655:
656:
657:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>