Package: pypfop
Document preprocessor forApache FOP.How does it works?It does what the huge title is implying, preprocess ahigherlevel template
to generatedynamicallyan specificXSL-FOdocument, which then gets
fed toApache FOPand generate the expected output. So that means that
this packagesrequires Java>_<', but fear not!, it is almost transparent
to the python application.In general the internal workflow is:template ->  mako -> apply css ->  xsl-fo ->  fop -> *Document*InstallationInstall pypfop:pip install pypfopInstallApache FOP:Download the binary package of fop1.1 either theziportarpackage.Decompress in wherever place you like and set environment variableFOP_CMDto thebin/fopof the decompressed folder.[1]UsageThe MarkupThe markup used to generate the documents is almost the same as the xsl-fo, the only
difference is that is not necessary to set the xml namespace to all the elements,
for example:<fo:table>
 <fo:table-header>
    <fo:table-row>
       <fo:table-cell>
         <fo:block>Project</fo:block>
       </fo:table-cell>
    </fo:table-row>
 </fo:table-header>
 <fo:table-body>
    <fo:table-row>
      <fo:table-cell>
         <fo:block>pypfop</fo:block>
     </fo:table-cell>
    </fo:table-row>
 </fo:table-body>
</fo:table>can be written like this:<table>
 <table-header>
    <table-row>
       <table-cell>
         <block>Project</block>
       </table-cell>
    </table-row>
 </table-header>
 <table-body>
    <table-row>
      <table-cell>
         <block>pypfopp</block>
     </table-cell>
    </table-row>
 </table-body>
</table>The higher level template languageAt the time the only supported template language ismakoit should not be very
complicated to extend to your favorite template language based in the implementation
of mako (which is pretty straight forward) and hopefully contribute back to the project :).For example the previous table can be generated with this mako template assuming theheaderandrowsvariables are passed to theDocument.generatemethod:<table>
  <table-header>
    <table-row>
      % for name in header:
      <table-cell>
        <block>${name}</block>
      </table-cell>
      % endfor
    </table-row>
  </table-header>
  <table-body>
    % for row in rows:
       <table-row>
     % for cell in row:
        <table-cell>
          <block>${cell}</block>
        </table-cell>
     % endfor
       </table-row>
    % endfor
  </table-body>
</table>SkeletonsThe previous examples are really just a fragment a document to be able to generate
a full document with metadata, paper size, margins, etc. To avoid the repetitive
work to write this kind of base document pypfop come with skeletons documents, the
purpose if this documents is to be inherited at each template, at the time
the only implemented skeleton is inpypfop/skeletons/mako/simple-letter-base.fo.mako,
which include place holders for metadata about the document and two regions, body
and footer, with a few defaults, which of course can be overwritten with the
appropriate parameters.To be a fully functional template for pypfop the previous table need to be like this.simple-table.fo.mako:<%inherit file="simple-letter-base.fo.mako" />
<table id="main-table">
  <table-header>
    <table-row>
      % for name in header:
      <table-cell>
        <block>${name}</block>
      </table-cell>
      % endfor
    </table-row>
  </table-header>
  <table-body>
    % for row in rows:
       <table-row>
     % for cell in row:
        <table-cell>
          <block>${cell}</block>
        </table-cell>
     % endfor
       </table-row>
    % endfor
  </table-body>
</table>The skeletons directory is set in the template directory path by default.Format and style with CSSBeside thehigher level languagethat define the content and layout of the document,
the style and formatting useCSS, to be more specific it can  parse the rules thatcssutilssupport, which are a very good subset of CSS2 and CSS3, for example it support
things like:nth-child(X)and@import url(XX).The properties that can be set are the same as in the specification of xsl-fo,
check out the section ofAbout XSL-FO syntax, with the only exception that you can
use classes as selectors, xsl-fo does not support theclassattribute,
the pypfop parser is going to look for theclassattribute then substitute with the
specific style and then remove theclassattribute.For example I could define the style for the previous table in three files.simple_table.css:@import url("general.css");
@import url("colors.css");

#main-table > table-header > table-row{
    text-align: center;
    font-weight: bold;
}

#main-table > table-header table-cell{
    padding: 2mm 0 0mm;
}general.css:flow[flow-name="xsl-region-body"] {
    font-size: 10pt;
    font-family: Helvetica;
}colors.css:#main-table> table-body > table-row > table-cell:first-child{
    color: red;
}
#main-table> table-body > table-row > table-cell:nth-child(2){
    color: blue;
}
#main-table> table-body > table-row > table-cell:nth-child(3){
    color: cyan;
}
#main-table> table-body > table-row > table-cell:last-child{
    color: green;
}Generate the documentThere are a few different ways to implement theDocumentclass,
but for the sake of simplicity this is a way to generate the document:from pypfop import Document
from pypfop.makotemplates import TemplateFactory

tfactory = TemplateFactory()
params = {'header': ['Project', 'Website', 'Language', 'Notes'],
          'rows': [('pypfop', 'https://bitbucket.org/cyraxjoe/pypfop',
                    'Python', 'Abstraction on top of Apache FOP'),
                    ('Apache FOP', 'https://xmlgraphics.apache.org/fop/',
                    'Java', '')] }
doc = Document(tfactory('simple-table.fo.mako'), 'simple_table.css')
print(doc.generate(params)) # returns the path of the generated file.Supported Document formatsIn the previous example we didn’t define the output of theDocumentin that case
the default output ofpdfis used, but the supported outputs are the same as
inApache FOP output formats.Frompypfop.__init__:VALID_OFORMATS = frozenset(('awt', 'pdf', 'mif', 'rtf',
                            'tiff', 'png', 'pcl', 'ps', 'txt'))The output format can be set inDocument.__init__orDocument.generatedoc = Document(tfactory('simple-table.fo.mako'), 'simple_table.css',
               oformat='rtf')ordoc.generate(params, oformat='rtf')About XSL-FO syntaxAs you should notice already it is required to know how to format xsl-fo documents
which in most part are very similar to the HTML counterparts (except that anything needs
to be inblocktags), the best reference that I could find online is in theXML Bible.Why!This project it use to be part of a larger project of one of my customers,
which I decide early on that I will useonly python 3, terrible decision
if you want to generate pdf files easily or at least at the moment.
I was looking to have some kind oftemplateto the very rigid format of
the average invoice and billing order, so pypfop came to relieve that pain.[1]Actually you can set the command at another level, check theDocumentclass.