One of the functions being available by default in any POD context is the xhtml function. Used via a from clause (see the previous section), this function allows to convert chunks of XHTML code (generally passed as strings) into chunks of ODF code within the resulting ODT document. This functionality is useful when using POD with, for example, the "web framework" part of Appy, that store some data in XHTML format, like content encoded via ckeditor fields.
Suppose you want to render this chunk of XHTML code at some place in your POD result.
XHTML code |
XHTML rendering (raw) |
<p>Te<b>s</b>t1 : <b>bold</b>, i<i>tal</i>ics, exponent<sup>34</sup>, sub<sub>45</sub>.</p> <p>An <a href="http://www.google.com">hyperlink</a> to Google.</p> <ol><li>Number list, item 1</li> <ol><li>Sub-item 1</li><li>Sub-Item 2</li> <ol><li>Sub-sub-item A</li><li>Sub-sub-item B <i>italic</i>.</li></ol> </ol> </ol> <ul><li>A bullet</li> <ul><li>A sub-bullet</li> <ul><li>A sub-sub-bullet</li></ul> <ol><li>A sub-sub number</li><li>Another.<br /></li></ol> </ul> </ul> <h2>Heading</h2> <p>Text<p> <h3>SubHeading</h3> <p>Subheading text</p> |
|
Define the following POD template. Variable xhtmlChunk contains the XHTML code shown above, as a string.
The rendering produces this document.
The OpenDocument rendering is a bit different than the XHTML rendering shown above. This is because POD uses the styles found in the POD template and tries to make a correspondence between style information in the XHTML chunk and styles present in the POD template. By default, when pod encounters an XHTML tag:
- it checks if a "class" attribute is defined on this tag. If yes, and if a style with the same "display name" is found in the OpenDocument template, this style will be used. The "display name" of an OpenDocument style is the name of the style as it appears in LibreOffice;
- if no "class" attribute is present, and if the XHTML tag is a heading (h1 to h6), POD tries to find an OpenDocument style which has the same outline level. For example, tag h1 may be mapped to style Heading 1. This is what happened in the example above;
- else, no style at all is applied.
You have the possibility to customize this behaviour by defining styles mappings.
Style mappings
You can define styles mappings at two different levels. The first, global, level, consists in defined a styles mapping when creating a Renderer instance, in parameter stylesMapping. A styles mapping is, basically, a Python dictionary whose keys are either CSS class names or XHTML element names, and whose values are display names of OpenDocument styles that must be present in the POD template. Every time you invoke the xhtml function in a POD template, the global styles mapping comes into play.
Note that in an OpenDocument document, LibreOffice stores only the styles that are used in the document. The styles names ("Heading 1", "Standard"...) that appear when opening your template with LibreOffice are thus a super-set of the styles that are actually stored into your document. You may consult the list of available styles in your POD template programmatically by calling your POD Renderer's getStyles method.
Ensure styles are stored in your POD templates
If the style you want to use is not stored in the POD template, a solution is to define a section with a series of paragraphs onto which you apply the styles you want to be included in the template. On this section, you set this POD statement:
do section if False
That way, the section and its content will never be rendered in any POD result; but the styles applied to its inner paragraphs will be stored in your POD template.
Here is an example.
The first section will not appear at all in the result, but thanks to the paragraphs defined in it, the following styles will be stored in the POD template: Highlight, ArtSectionBold and ArtSectionItalic.
In the rendered part of the template (in the example, it represents a single paragraph, the last one), any XHTML paragraph tag defined with a class attribute referring to any of these names will produce, in the POD result, a paragraph onto which the homonym style will be applied.
Key « h* »
In a styles mapping, you can also define a special key, h*, and define, as value, a positive or negative integer. When POD tries to establish a style correspondance based on outline level, it will use this number. For example, if you specify the following styles mapping,
{'h*':-1}
, when encountering tag h2 (provided it does not define a "class" attribute), if an OpenDocument style with an outlevel of 2-1=1 is found (ie, "Heading 1"), it will be used.
Local styles mappings
Beyond the unique, Renderer-wide global styles mapping, each time you invoke the xhtml function in a POD template, you may specify a local styles mapping in the parameter named stylesMapping, like shown below.
Local styles mappings override what you have (potentially) defined in the global styles mapping.
Current restrictions
At present, the XHTML "a" tag may not be "styled-mapped" (it may not be present in styles mappings) because POD uses it own automatically-generated OpenDocument style.
Styles mapping – Reference
There are a lot more possibilities with styles mappings. The complete reference is found in code comments, on method checkStylesMapping defined on class StylesManager from file appy/pod/styles_manager.py. This method's signature and documentation are shown below.
def checkStylesMapping(self, stylesMapping):
'''Checks that the given stylesMapping is correct, and returns the
internal representation of it.'''
You have noticed that, for tables and (bulleted and numbered) lists, the mapping can be so complex that is is defined via a specific class.
Styles mappings for tables – class TableProperties
Within a styles mapping, at key 'table', the specified value must be an instance of class TableProperties. This class, to be found in file appy/pod/styles_manager.py, has the following constructor.
def __init__(self, pageWidth=None, px2cm=css.px2cm, cellPx2cm=10.0,
wideAbove=495, minColumnWidth=0.07, columnModifier=None,
minCellPadding=0.0, cellContentStyle='podCellContent',
headerContentStyle='podHeaderCellContent', margins=defaultMargins,
unbreakable=False, unbreakableRows=False, border=None,
prevails=False):
self.pageWidth = pageWidth
self.px2cm = px2cm
self.cellPx2cm = cellPx2cm
self.wideAbove = wideAbove
self.minColumnWidth = minColumnWidth
self.columnModifier = columnModifier
self.minCellPadding = minCellPadding
self.cellContentStyle = cellContentStyle
self.headerContentStyle = headerContentStyle
self.margins = margins
self.unbreakable = unbreakable
self.unbreakableRows = unbreakableRows
self.border = border
self.prevails = prevails
Static attribute defaultMargins used as default value for attribute margins, is the following.
defaultMargins = (0.3, 0.0, 0.3, 0.0)
If you do not define any 'table' key in any styles mapping, a default TableProperties instance will be used, having the default values as defined in the hereabove constructor.
Styles mappings for lists – classes BulletedProperties and NumberedProperties
Within a styles mapping, at keys 'ul' and 'ol', you may define, respectively, instances of classes BulletedProperties and NumberedProperties. These two classes inherit from class ListProperties having the following constructor.
def __init__(self, levels, formats, delta, firstDelta, space, paraStyle):
self.levels = levels
self.formats = formats
self.delta = delta
self.firstDelta = firstDelta
self.space = space
self.paraStyle = paraStyle
Class BulletedProperties defines default values for this base constructor, as shown below.
def __init__(self, levels=4, formats=defaultFormats,
delta=0.32, firstDelta=0.08, space=0.16, paraStyle=None):
Static attribute defaultFormats lists the UTF-8 characters used to render bullets at various levels. The default list of such chars is
defaultFormats = ('•', '◦', '▪')
These formats are recursively used at deeper levels. For example, at the 4th bullet level, the first character in this list will again be used.
Similarly, class NumberedProperties also defines default values for all attributes of the base constructor.
def __init__(self, levels=4, formats=defaultFormats,
suffixes=defaultSuffixes, delta=0.32, firstDelta=0.08,
space=0.16, paraStyle=None):
For this class, static attribute defaultFormats is simply:
defaultFormats = ('1',)
It means that this numeric format is used at any level. Moreover, an additional concept is in use here, compared to bulleted lists: after each format character, a suffix may be defined. The constructor has an addtional parameter named suffixes, whose default value is:
defaultSuffixes = ('.',)
With these default settings, a numbered list with 2 levels will be rendered that way:
1. First level item A
1.1. Sub 1
1.2. Sub 2
2. First level, item B
Other numbering schemes can be used. The following table describes the most commonly used schemes, but more exist (see LibreOffice documentation).
Format character |
Numbering scheme |
1 |
Arabic numerals, 1, 2, 3... |
A |
A, B, C... |
a |
a, b, c... |
I |
Uppercase roman literals: I, II, III, IV... |
i |
Lowercase roman literals: i, ii, iii, iv... |
1st |
Special rendering: 1st, 2nd... |
For example, if you want to produce this list:
a) first case
b) second case
Define the following NumberedProperties instance:
NumberedProperties(formats=('a',), suffixes=(')',)
If you do not define any 'ul' / 'ol' key in any styles mapping, a default BulletedProperties / NumberedProperties instance will be used, having the default values as defined in the hereabove constructors.
Do not use the xhtml function in POD expressions
You might be tempted to use the xhtml function in a POD expression. This will work but will not produce the expected result: the XHTML code will not be interpreted (it will be escaped) and will appear as is in the ODT result.
Reference
The xhtml function as available in the default POD context corresponds to method renderXhtml defined on class Renderer.
def renderXhtml(self, s, stylesMapping={}, keepWithNext=0,
keepImagesRatio=False, imagesMaxWidth='page',
imagesMaxHeight='page', html=None, inject=False,
unwrap=False, stylesStore=None):
'''Method that can be used (under the name "xhtml") into a POD template
for converting a chunk of XHTML content (s) into a chunk of ODF
content.'''