work in progress: read properties from Office documents and update version field if appropriate

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3926 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2010-07-27 09:50:19 +00:00
parent 2fb16b5c24
commit 9091b56c69
3 changed files with 54 additions and 10 deletions

View file

@ -214,9 +214,15 @@ Uploading Resources with HTTP PUT Requests
Extracting Document Properties from MS Office Files Extracting Document Properties from MS Office Files
=================================================== ===================================================
>>> import shutil
>>> from loops.resource import Resource >>> from loops.resource import Resource
>>> tOfficeFile = concepts['officefile'] >>> tOfficeFile = concepts['officefile']
>>> path = os.path.join(dataDir, 'office') >>> path = os.path.join(dataDir, 'office')
>>> fn = os.path.join(path, 'example.docx')
>>> shutil.copy(fn + '.sav', fn)
>>> os.path.getsize(fn)
195808L
>>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx', >>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx',
... title=u'Example Word File', resourceType=tOfficeFile, ... title=u'Example Word File', resourceType=tOfficeFile,
... storageParams=dict(subdirectory=path)) ... storageParams=dict(subdirectory=path))
@ -225,7 +231,7 @@ Extracting Document Properties from MS Office Files
>>> content = aOfficeFile.data >>> content = aOfficeFile.data
>>> len(content) >>> len(content)
195808 192925
Fin de partie Fin de partie

View file

@ -22,8 +22,9 @@ Resource adapter(s) for MS Office files.
$Id$ $Id$
""" """
from xml.dom.minidom import parseString from lxml import etree
from zipfile import ZipFile from zipfile import ZipFile
import shutil
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope import component from zope import component
from zope.component import adapts from zope.component import adapts
@ -36,6 +37,7 @@ from loops.integrator.interfaces import IOfficeFile
from loops.interfaces import IResource, IExternalFile from loops.interfaces import IResource, IExternalFile
from loops.resource import ExternalFileAdapter from loops.resource import ExternalFileAdapter
from loops.type import TypeInterfaceSourceList from loops.type import TypeInterfaceSourceList
from loops.versioning.interfaces import IVersionable
TypeInterfaceSourceList.typeInterfaces += (IOfficeFile,) TypeInterfaceSourceList.typeInterfaces += (IOfficeFile,)
@ -48,7 +50,8 @@ class OfficeFile(ExternalFileAdapter):
implements(IOfficeFile) implements(IOfficeFile)
propertyMap = dict(version=u'Revision:') propertyMap = {u'Revision:': 'version'}
propFileName = 'docProps/custom.xml'
def setExternalAddress(self, addr): def setExternalAddress(self, addr):
super(OfficeFile, self).setExternalAddress(addr) super(OfficeFile, self).setExternalAddress(addr)
@ -60,13 +63,46 @@ class OfficeFile(ExternalFileAdapter):
storage = component.getUtility(IExternalStorage, name=self.storageName) storage = component.getUtility(IExternalStorage, name=self.storageName)
subDir = self.storageParams.get('subdirectory') subDir = self.storageParams.get('subdirectory')
fn = storage.getDir(self.externalAddress, subDir) fn = storage.getDir(self.externalAddress, subDir)
# TODO: check if suitable file type (.docx, .xlsm)
# open ZIP file, process properties, set version property in file # open ZIP file, process properties, set version property in file
zf = ZipFile(fn, 'a') zf = ZipFile(fn, 'r')
#print '***', zf.namelist() #print '***', zf.namelist()
propsXml = zf.read('docProps/custom.xml') propsXml = zf.read(self.propFileName)
dom = parseString(propsXml) dom = etree.fromstring(propsXml)
props = dom.getElementsByTagName('property') changed = False
for p in props: docVersion = None
pass version = IVersionable(self.context).versionId
#print '***', p.getAttribute('name'), p.childNodes[0].childNodes[0].data strType = ('{http://schemas.openxmlformats.org/'
'officeDocument/2006/docPropsVTypes}lpwstr')
attributes = {}
for p in dom:
name = p.attrib.get('name')
value = p[0].text
#print '***', name, value, p[0].tag
attr = self.propertyMap.get(name)
if attr == 'version':
docVersion = value
if docVersion and docVersion != version:
# update XML
p[0] = etree.Element(strType)
p[0].text = version
changed = True
elif attr is not None:
attributes[attr] = value
zf.close() zf.close()
if changed:
newFn = fn + '.new'
zf = ZipFile(fn, 'r')
newZf = ZipFile(newFn, 'w')
for info in zf.infolist():
name = info.filename
if name != self.propFileName:
newZf.writestr(info, zf.read(name))
newZf.writestr(self.propFileName, etree.tostring(dom))
newZf.close()
shutil.move(newFn, fn)
self.update(attributes)
def update(self, attributes):
# to be implemented by subclass
pass

View file

@ -21,6 +21,7 @@ from loops.integrator.office.base import OfficeFile
from loops.knowledge.setup import SetupManager as KnowledgeSetupManager from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
from loops.setup import SetupManager, addAndConfigureObject from loops.setup import SetupManager, addAndConfigureObject
from loops.tests.setup import TestSite as BaseTestSite from loops.tests.setup import TestSite as BaseTestSite
from loops.versioning.versionable import VersionableResource
dataDir = os.path.join(os.path.dirname(__file__), 'testdata') dataDir = os.path.join(os.path.dirname(__file__), 'testdata')
@ -37,6 +38,7 @@ class TestSite(BaseTestSite):
component.provideAdapter(FileAdapter, provides=IFile) component.provideAdapter(FileAdapter, provides=IFile)
component.provideAdapter(ExternalFileAdapter, provides=IExternalFile) component.provideAdapter(ExternalFileAdapter, provides=IExternalFile)
component.provideAdapter(OfficeFile, provides=IOfficeFile) component.provideAdapter(OfficeFile, provides=IOfficeFile)
component.provideAdapter(VersionableResource)
component.provideUtility(fullPathStorage(), IExternalStorage, name='fullpath') component.provideUtility(fullPathStorage(), IExternalStorage, name='fullpath')