示例#1
0
    def __init__(self, template, context, result, pythonWithUnoPath=None,
      ooPort=2002, stylesMapping={}, forceOoCall=False, finalizeFunction=None,
      overwriteExisting=False, raiseOnError=False, imageResolver=None,
      stylesTemplate=None, optimalColumnWidths=False, script=None,
      renamePageStyles=False):
        '''This Python Open Document Renderer (PodRenderer) loads a document
           template (p_template) which is an ODT or ODS file with some elements
           written in Python. Based on this template and some Python objects
           defined in p_context, the renderer generates an ODT file (p_result)
           that instantiates the p_template and fills it with objects from the
           p_context.

         - If p_result does not end with .odt or .ods, the Renderer will call
           LibreOffice to perform a conversion. If p_forceOoCall is True, even
           if p_result ends with .odt, LibreOffice will be called, not for
           performing a conversion, but for updating some elements like indexes
           (table of contents, etc) and sections containing links to external
           files (which is the case, for example, if you use the default
           function "document").

         - If the Python interpreter which runs the current script is not
           UNO-enabled, this script will run, in another process, a UNO-enabled
           Python interpreter (whose path is p_pythonWithUnoPath) which will
           call LibreOffice. In both cases, we will try to connect to
           LibreOffice in server mode on port p_ooPort.

         - If you plan to make "XHTML to OpenDocument" conversions (via the POD
           function "xhtml"), you may specify a styles mapping in
           p_stylesMapping.

         - If you specify a function in p_finalizeFunction, this function will
           be called by the renderer before re-zipping the ODT/S result. This
           way, you can still perform some actions on the content of the ODT/S
           file before it is zipped and potentially converted. This function
           must accept 2 args:
            * the absolute path to the temporary folder, containing the
              un-zipped content of the ODT/S result;
            * the Renderer instance.

         - If you set p_overwriteExisting to True, the renderer will overwrite
           the result file. Else, an exception will be thrown if the result file
           already exists.

         - If p_raiseOnError is False (the default value), any error encountered
           during the generation of the result file will be dumped into it, as
           a Python traceback within a note. Else, the error will be raised.

         - p_imageResolver allows POD to retrieve images, from "img" tags within
           XHTML content. Indeed, POD may not be able (ie, may not have the
           permission to) perform a HTTP GET on those images. Currently, the
           resolver can only be a Zope application object.

         - p_stylesTemplate can be the path to a LibreOffice file (ie, a .ott
           file) whose styles will be imported within the result.

         - p_optimalColumnWidths corresponds to the homonym option to
           converter.py, excepted that values "True" or "False" must be boolean
           values. Note that the POD function "xhtml" requires this parameter to
           be "OCW_.*" to be fully operational. When optimalColumnWidths is not
           False, forceOoCall is forced to True.

         - p_script is the absolute path to a Python script containing functions
           that the converter will call in order to customize the process of
           manipulating the document via the LibreOffice UNO interface. For more
           information, see appy/pod/converter.py, option "-s". Note that when
           such p_script is specified, p_forceOoCall is forced to True.

         - If this document is a sub-document to be included in a master one, it
           has sense to set parameter p_renamePageStyles to True. This way, when
           importing it into the master document, all page styles will be
           considered different and tied elements like headers and footers will
           correctly be imported into the master document. The "do... pod"
           statement automatically sets this parameter to True.
        '''
        self.template = template
        self.result = result
        self.contentXml = None # Content (string) of content.xml
        self.stylesXml = None # Content (string) of styles.xml
        self.stylesManager = None # Manages the styles defined into the ODT
        # template
        self.tempFolder = None
        self.env = None
        self.pyPath = pythonWithUnoPath
        self.ooPort = ooPort
        # p_forceOoCall may be forced to True
        self.forceOoCall = forceOoCall or \
                           bool(optimalColumnWidths) or bool(script)
        self.finalizeFunction = finalizeFunction
        self.overwriteExisting = overwriteExisting
        self.raiseOnError = raiseOnError
        self.imageResolver = imageResolver
        self.stylesTemplate = stylesTemplate
        self.optimalColumnWidths = optimalColumnWidths
        self.script = script
        self.renamePageStyles = renamePageStyles
        # Keep trace of the original context given to the renderer
        self.originalContext = context
        # Remember potential files or images that will be included through
        # "do ... from document" statements: we will need to declare them in
        # META-INF/manifest.xml. Keys are file names as they appear within the
        # ODT file (to dump in manifest.xml); values are original paths of
        # included images (used for avoiding to create multiple copies of a file
        # which is imported several times).
        self.fileNames = {}
        self.prepareFolders()
        # Unzip template
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
        os.mkdir(self.unzipFolder)
        info = unzip(template, self.unzipFolder, odf=True)
        self.contentXml = info['content.xml']
        self.stylesXml = info['styles.xml']
        self.stylesManager = StylesManager(self)
        # From LibreOffice 3.5, it is not possible anymore to dump errors into
        # the resulting ods as annotations. Indeed, annotations can't reside
        # anymore within paragraphs. ODS files generated with pod and containing
        # error messages in annotations cause LibreOffice 3.5 and 4.0 to crash.
        # LibreOffice >= 4.1 simply does not show the annotation.
        if info['mimetype'] == utils.mimeTypes['ods']: self.raiseOnError = True
        # Create the parsers for content.xml and styles.xml
        nso = PodEnvironment.NS_OFFICE
        for name in ('content', 'styles'):
            styleTag = (name == 'content') and 'automatic-styles' or 'styles'
            inserts = (
              OdInsert(POD_FONTS, XmlElement('font-face-decls', nsUri=nso)),
              OdInsert(POD_STYLES[name], XmlElement(styleTag, nsUri=nso)))
            parser = self.createPodParser('%s.xml' % name, context, inserts)
            setattr(self, '%sParser' % name, parser)
        # Store the styles mapping
        self.setStylesMapping(stylesMapping)
        # While working, POD may identify "dynamic styles" to insert either in
        # the "automatic-styles" section of content.xml (ie, the column styles
        # of tables generated from XHTML tables via xhtml2odt.py), or in the
        # "styles" section of styles.xml (ie, bullet styles).
        self.dynamicStyles = {'content': [], 'styles': []}
示例#2
0
    def __init__(self, template, context, result, pythonWithUnoPath=None,
                 ooPort=2002, stylesMapping={}, forceOoCall=False,
                 finalizeFunction=None, overwriteExisting=False,
                 raiseOnError=False, imageResolver=None):
        '''This Python Open Document Renderer (PodRenderer) loads a document
           template (p_template) which is an ODT or ODS file with some elements
           written in Python. Based on this template and some Python objects
           defined in p_context, the renderer generates an ODT file (p_result)
           that instantiates the p_template and fills it with objects from the
           p_context.

         - If p_result does not end with .odt or .ods, the Renderer will call
           LibreOffice to perform a conversion. If p_forceOoCall is True, even
           if p_result ends with .odt, LibreOffice will be called, not for
           performing a conversion, but for updating some elements like indexes
           (table of contents, etc) and sections containing links to external
           files (which is the case, for example, if you use the default
           function "document").

         - If the Python interpreter which runs the current script is not
           UNO-enabled, this script will run, in another process, a UNO-enabled
           Python interpreter (whose path is p_pythonWithUnoPath) which will
           call LibreOffice. In both cases, we will try to connect to
           LibreOffice in server mode on port p_ooPort.

         - If you plan to make "XHTML to OpenDocument" conversions, you may
           specify a styles mapping in p_stylesMapping.

         - If you specify a function in p_finalizeFunction, this function will
           be called by the renderer before re-zipping the ODT/S result. This
           way, you can still perform some actions on the content of the ODT/S
           file before it is zipped and potentially converted. This function
           must accept one arg: the absolute path to the temporary folder
           containing the un-zipped content of the ODT/S result.

         - If you set p_overwriteExisting to True, the renderer will overwrite
           the result file. Else, an exception will be thrown if the result file
           already exists.

         - If p_raiseOnError is False (the default value), any error encountered
           during the generation of the result file will be dumped into it, as
           a Python traceback within a note. Else, the error will be raised.

         - p_imageResolver allows POD to retrieve images, from "img" tags within
           XHTML content. Indeed, POD may not be able (ie, may not have the
           permission to) perform a HTTP GET on those images. Currently, the
           resolver can only be a Zope application object.
        '''
        self.template = template
        self.templateZip = zipfile.ZipFile(template)
        self.result = result
        self.contentXml = None # Content (string) of content.xml
        self.stylesXml = None # Content (string) of styles.xml
        self.stylesManager = None # Manages the styles defined into the ODT
        # template
        self.tempFolder = None
        self.env = None
        self.pyPath = pythonWithUnoPath
        self.ooPort = ooPort
        self.forceOoCall = forceOoCall
        self.finalizeFunction = finalizeFunction
        self.overwriteExisting = overwriteExisting
        self.raiseOnError = raiseOnError
        self.imageResolver = imageResolver
        # Remember potential files or images that will be included through
        # "do ... from document" statements: we will need to declare them in
        # META-INF/manifest.xml. Keys are file names as they appear within the
        # ODT file (to dump in manifest.xml); values are original paths of
        # included images (used for avoiding to create multiple copies of a file
        # which is imported several times).
        self.fileNames = {}
        self.prepareFolders()
        # Unzip template
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
        os.mkdir(self.unzipFolder)
        for zippedFile in self.templateZip.namelist():
            # Before writing the zippedFile into self.unzipFolder, create the
            # intermediary subfolder(s) if needed.
            fileName = None
            if zippedFile.endswith('/') or zippedFile.endswith(os.sep):
                # This is an empty folder. Create it nevertheless. If zippedFile
                # starts with a '/', os.path.join will consider it an absolute
                # path and will throw away self.unzipFolder.
                os.makedirs(os.path.join(self.unzipFolder,
                                         zippedFile.lstrip('/')))
            else:
                fileName = os.path.basename(zippedFile)
                folderName = os.path.dirname(zippedFile)
                fullFolderName = self.unzipFolder
                if folderName:
                    fullFolderName = os.path.join(fullFolderName, folderName)
                    if not os.path.exists(fullFolderName):
                        os.makedirs(fullFolderName)
            # Unzip the file in self.unzipFolder
            if fileName:
                fullFileName = os.path.join(fullFolderName, fileName)
                f = open(fullFileName, 'wb')
                fileContent = self.templateZip.read(zippedFile)
                if (fileName == 'content.xml') and not folderName:
                    # content.xml files may reside in subfolders.
                    # We modify only the one in the root folder.
                    self.contentXml = fileContent
                elif (fileName == 'styles.xml') and not folderName:
                    # Same remark as above.
                    self.stylesManager = StylesManager(fileContent)
                    self.stylesXml = fileContent
                elif (fileName == 'mimetype') and \
                     (fileContent == mimeTypes['ods']):
                    # From LibreOffice 3.5, it is not possible anymore to dump
                    # errors into the resulting ods as annotations. Indeed,
                    # annotations can't reside anymore within paragraphs. ODS
                    # files generated with pod and containing error messages in
                    # annotations cause LibreOffice 3.5 and 4.0 to crash.
                    # LibreOffice >= 4.1 simply does not show the annotation.
                    self.raiseOnError = True
                f.write(fileContent)
                f.close()
        self.templateZip.close()
        # Create the content.xml parser
        pe = PodEnvironment
        contentInserts = (
            OdInsert(CONTENT_POD_FONTS,
                XmlElement('font-face-decls', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'svg': pe.NS_SVG}),
            OdInsert(CONTENT_POD_STYLES,
                XmlElement('automatic-styles', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'fo': pe.NS_FO,
                        'text': pe.NS_TEXT, 'table': pe.NS_TABLE}))
        self.contentParser = self.createPodParser('content.xml', context,
                                                  contentInserts)
        # Create the styles.xml parser
        stylesInserts = (
            OdInsert(STYLES_POD_FONTS,
                XmlElement('font-face-decls', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'svg': pe.NS_SVG}),
            OdInsert(STYLES_POD_STYLES,
                XmlElement('styles', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'fo': pe.NS_FO,
                        'text': pe.NS_TEXT}))
        self.stylesParser = self.createPodParser('styles.xml', context,
                                                 stylesInserts)
        # Store the styles mapping
        self.setStylesMapping(stylesMapping)
        # While working, POD may identify "dynamic styles" to insert into
        # the "automatic styles" section of content.xml, like the column styles
        # of tables generated from XHTML tables via xhtml2odt.py.
        self.dynamicStyles = []
示例#3
0
    def __init__(self,
                 template,
                 context,
                 result,
                 pythonWithUnoPath=None,
                 ooPort=2002,
                 stylesMapping={},
                 forceOoCall=False,
                 finalizeFunction=None,
                 overwriteExisting=False):
        '''This Python Open Document Renderer (PodRenderer) loads a document
        template (p_template) which is an ODT file with some elements
        written in Python. Based on this template and some Python objects
        defined in p_context, the renderer generates an ODT file
        (p_result) that instantiates the p_template and fills it with objects
        from the p_context.

         - If p_result does not end with .odt, the Renderer
           will call OpenOffice to perform a conversion. If p_forceOoCall is
           True, even if p_result ends with .odt, OpenOffice will be called, not
           for performing a conversion, but for updating some elements like
           indexes (table of contents, etc) and sections containing links to
           external files (which is the case, for example, if you use the
           default function "document").

         - If the Python interpreter which runs the current script is not
           UNO-enabled, this script will run, in another process, a UNO-enabled
           Python interpreter (whose path is p_pythonWithUnoPath) which will
           call OpenOffice. In both cases, we will try to connect to OpenOffice
           in server mode on port p_ooPort.

         - If you plan to make "XHTML to OpenDocument" conversions, you may
           specify a styles mapping in p_stylesMapping.

         - If you specify a function in p_finalizeFunction, this function will
           be called by the renderer before re-zipping the ODT result. This way,
           you can still perform some actions on the content of the ODT file
           before it is zipped and potentially converted. This function must
           accept one arg: the absolute path to the temporary folder containing
           the un-zipped content of the ODT result.

         - If you set p_overwriteExisting to True, the renderer will overwrite
           the result file. Else, an exception will be thrown if the result file
           already exists.'''
        self.template = template
        self.templateZip = zipfile.ZipFile(template)
        self.result = result
        self.contentXml = None  # Content (string) of content.xml
        self.stylesXml = None  # Content (string) of styles.xml
        self.stylesManager = None  # Manages the styles defined into the ODT
        # template
        self.tempFolder = None
        self.env = None
        self.pyPath = pythonWithUnoPath
        self.ooPort = ooPort
        self.forceOoCall = forceOoCall
        self.finalizeFunction = finalizeFunction
        self.overwriteExisting = overwriteExisting
        # Remember potential files or images that will be included through
        # "do ... from document" statements: we will need to declare them in
        # META-INF/manifest.xml. Keys are file names as they appear within the
        # ODT file (to dump in manifest.xml); values are original paths of
        # included images (used for avoiding to create multiple copies of a file
        # which is imported several times).
        # imported file).
        self.fileNames = {}
        self.prepareFolders()
        # Unzip template
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
        os.mkdir(self.unzipFolder)
        for zippedFile in self.templateZip.namelist():
            # Before writing the zippedFile into self.unzipFolder, create the
            # intermediary subfolder(s) if needed.
            fileName = None
            if zippedFile.endswith('/') or zippedFile.endswith(os.sep):
                # This is an empty folder. Create it nevertheless.
                os.makedirs(os.path.join(self.unzipFolder, zippedFile))
            else:
                fileName = os.path.basename(zippedFile)
                folderName = os.path.dirname(zippedFile)
                fullFolderName = self.unzipFolder
                if folderName:
                    fullFolderName = os.path.join(fullFolderName, folderName)
                    if not os.path.exists(fullFolderName):
                        os.makedirs(fullFolderName)
            # Unzip the file in self.unzipFolder
            if fileName:
                fullFileName = os.path.join(fullFolderName, fileName)
                f = open(fullFileName, 'wb')
                fileContent = self.templateZip.read(zippedFile)
                if (fileName == 'content.xml') and not folderName:
                    # content.xml files may reside in subfolders.
                    # We modify only the one in the root folder.
                    self.contentXml = fileContent
                elif (fileName == 'styles.xml') and not folderName:
                    # Same remark as above.
                    self.stylesManager = StylesManager(fileContent)
                    self.stylesXml = fileContent
                f.write(fileContent)
                f.close()
        self.templateZip.close()
        # Create the content.xml parser
        pe = PodEnvironment
        contentInserts = (OdInsert(CONTENT_POD_FONTS,
                                   XmlElement('font-face-decls',
                                              nsUri=pe.NS_OFFICE),
                                   nsUris={
                                       'style': pe.NS_STYLE,
                                       'svg': pe.NS_SVG
                                   }),
                          OdInsert(CONTENT_POD_STYLES,
                                   XmlElement('automatic-styles',
                                              nsUri=pe.NS_OFFICE),
                                   nsUris={
                                       'style': pe.NS_STYLE,
                                       'fo': pe.NS_FO,
                                       'text': pe.NS_TEXT,
                                       'table': pe.NS_TABLE
                                   }))
        self.contentParser = self.createPodParser('content.xml', context,
                                                  contentInserts)
        # Create the styles.xml parser
        stylesInserts = (OdInsert(STYLES_POD_FONTS,
                                  XmlElement('font-face-decls',
                                             nsUri=pe.NS_OFFICE),
                                  nsUris={
                                      'style': pe.NS_STYLE,
                                      'svg': pe.NS_SVG
                                  }),
                         OdInsert(STYLES_POD_STYLES,
                                  XmlElement('styles', nsUri=pe.NS_OFFICE),
                                  nsUris={
                                      'style': pe.NS_STYLE,
                                      'fo': pe.NS_FO
                                  }))
        self.stylesParser = self.createPodParser('styles.xml', context,
                                                 stylesInserts)
        # Stores the styles mapping
        self.setStylesMapping(stylesMapping)