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:
parent
2fb16b5c24
commit
9091b56c69
3 changed files with 54 additions and 10 deletions
|
@ -214,9 +214,15 @@ Uploading Resources with HTTP PUT Requests
|
|||
Extracting Document Properties from MS Office Files
|
||||
===================================================
|
||||
|
||||
>>> import shutil
|
||||
>>> from loops.resource import Resource
|
||||
>>> tOfficeFile = concepts['officefile']
|
||||
>>> 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',
|
||||
... title=u'Example Word File', resourceType=tOfficeFile,
|
||||
... storageParams=dict(subdirectory=path))
|
||||
|
@ -225,7 +231,7 @@ Extracting Document Properties from MS Office Files
|
|||
|
||||
>>> content = aOfficeFile.data
|
||||
>>> len(content)
|
||||
195808
|
||||
192925
|
||||
|
||||
|
||||
Fin de partie
|
||||
|
|
|
@ -22,8 +22,9 @@ Resource adapter(s) for MS Office files.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from xml.dom.minidom import parseString
|
||||
from lxml import etree
|
||||
from zipfile import ZipFile
|
||||
import shutil
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.component import adapts
|
||||
|
@ -36,6 +37,7 @@ from loops.integrator.interfaces import IOfficeFile
|
|||
from loops.interfaces import IResource, IExternalFile
|
||||
from loops.resource import ExternalFileAdapter
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
from loops.versioning.interfaces import IVersionable
|
||||
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (IOfficeFile,)
|
||||
|
@ -48,7 +50,8 @@ class OfficeFile(ExternalFileAdapter):
|
|||
|
||||
implements(IOfficeFile)
|
||||
|
||||
propertyMap = dict(version=u'Revision:')
|
||||
propertyMap = {u'Revision:': 'version'}
|
||||
propFileName = 'docProps/custom.xml'
|
||||
|
||||
def setExternalAddress(self, addr):
|
||||
super(OfficeFile, self).setExternalAddress(addr)
|
||||
|
@ -60,13 +63,46 @@ class OfficeFile(ExternalFileAdapter):
|
|||
storage = component.getUtility(IExternalStorage, name=self.storageName)
|
||||
subDir = self.storageParams.get('subdirectory')
|
||||
fn = storage.getDir(self.externalAddress, subDir)
|
||||
# TODO: check if suitable file type (.docx, .xlsm)
|
||||
# open ZIP file, process properties, set version property in file
|
||||
zf = ZipFile(fn, 'a')
|
||||
zf = ZipFile(fn, 'r')
|
||||
#print '***', zf.namelist()
|
||||
propsXml = zf.read('docProps/custom.xml')
|
||||
dom = parseString(propsXml)
|
||||
props = dom.getElementsByTagName('property')
|
||||
for p in props:
|
||||
pass
|
||||
#print '***', p.getAttribute('name'), p.childNodes[0].childNodes[0].data
|
||||
propsXml = zf.read(self.propFileName)
|
||||
dom = etree.fromstring(propsXml)
|
||||
changed = False
|
||||
docVersion = None
|
||||
version = IVersionable(self.context).versionId
|
||||
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()
|
||||
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
|
||||
|
|
|
@ -21,6 +21,7 @@ from loops.integrator.office.base import OfficeFile
|
|||
from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
|
||||
from loops.setup import SetupManager, addAndConfigureObject
|
||||
from loops.tests.setup import TestSite as BaseTestSite
|
||||
from loops.versioning.versionable import VersionableResource
|
||||
|
||||
dataDir = os.path.join(os.path.dirname(__file__), 'testdata')
|
||||
|
||||
|
@ -37,6 +38,7 @@ class TestSite(BaseTestSite):
|
|||
component.provideAdapter(FileAdapter, provides=IFile)
|
||||
component.provideAdapter(ExternalFileAdapter, provides=IExternalFile)
|
||||
component.provideAdapter(OfficeFile, provides=IOfficeFile)
|
||||
component.provideAdapter(VersionableResource)
|
||||
|
||||
component.provideUtility(fullPathStorage(), IExternalStorage, name='fullpath')
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue