XSLT and XSL-FO flexibility allows for support of a variety of use-cases. Stylesheets must be developed with stylesheet dynamics in mind. XSL stylesheet authors should follow notes below to create stylesheets which make document authoring easy and convenient.
For example, the following template generates representation that in some cases may not allow element content to be edited:
<xsl:template match="member"> <xsl:apply-templates/> </xsl:template>
The correct template is:
<xsl:template match="member"> <fo:inline><xsl:apply-templates/></fo:inline> </xsl:template>
The idea is that Serna binds a generated FO (here fo:inline) to the node matching the template (here member). Therefore Serna learns element name and cursor location from the area generated by the template matched to the element. If the template generated no areas, but some content, Serna cannot know exactly to which source element the generated content belongs.
For example, the result of the following template will be incorrectly displayed:
<xsl:template match="section"> <xsl:apply-templates select="title"/> <fo:block> <xsl:apply-templates select="*"/> </fo:block> </xsl:template>
Serna will render title as the child of section's parent, but not as a child of its section. The correct way is:
<xsl:template match="section"> <fo:block> <xsl:apply-templates select="title"/> <xsl:apply-templates select="*"/> </fo:block> </xsl:template>
Serna will understand that title belongs to section because title will be inside fo:block bound to section 's template.
The following will be represented as if there are two important elements, though there is one that generated two blocks:
<xsl:template match="important"> <fo:block start-indent="0.25in""> <xsl:text>IMPORTANT: </xsl:text> <xsl:apply-templates select="title"/> </fo:block> <fo:block> <xsl:apply-templates select="*[local-name(.) != 'title']"/> </fo:block> </xsl:template>
The correct way is:
<xsl:template match="important"> <fo:block> <fo:block start-indent="0.25in""> <xsl:text>IMPORTANT: </xsl:text> <xsl:apply-templates select="title"/> </fo:block> <fo:block> <xsl:apply-templates select="*[local-name(.) != 'title']"/> </fo:block> </fo:block> </xsl:template>
Serna represents empty FOs as empty elements. Therefore in situations when the element may have empty content make sure that empty FOs will be not generated. The following representation will confuse the user if title is not required:
<xsl:template name="titled-block"> <fo:block start-indent="0.25in"> <xsl:apply-templates select="title"/> </fo:block> <fo:block> <xsl:apply-templates select="*[local-name(.) != 'title']"/> </fo:block> </xsl:template>
The correct way is:
<xsl:template name="titled-block"> <xsl:if test="title"> <fo:block start-indent="0.25in"> <xsl:apply-templates select="title"/> </fo:block> </xsl:if> <fo:block> <xsl:apply-templates select="*[local-name(.) != 'title']"/> </fo:block> </xsl:template>
Sometimes it is convenient to generate some text when representing an element. But make sure you generate text when element is not empty, this will be more convenient for the user. For example:
<xsl:template match="seealso"> <fo:inline> <xsl:text>See also:</xsl:text> <xsl:apply-templates/> </fo:inline> </xsl:template>
This will generate text " See also:" when the user inserted an empty seealso tag, and it will be a little tiresome for the user to find the position inside seealso for inserting elements. A better approach is:
<xsl:template match="seealso"> <fo:inline> <xsl:if test="text()"> <xsl:text>See also:</xsl:text> </xsl:if> <xsl:apply-templates/> </fo:inline> </xsl:template>
Then when the user inserts an empty seealso he will see an empty tag, and the text " See also:" will appear when he inserts the first symbol.