Adapt Saxon-CE event model to XSL-FO?

Inasmuch as the Print and Page Layout Community Group at the W3C is looking at how to get feedback from the XSL formatter and I’ve also been reading about how Saxon-CE handles user input, I’m now wondering whether the same sort of pattern could be adapted to handling feedback from the XSL formatter. Saxon-CE does it through template rules that match the element that receives the event and are in a mode that reflects the type of event, and similarly an XSL formatter could trigger on exceptional events such as overflow occurring or even on mundane events such as completion of a page sequence, and the templates in the corresponding modes could match on either FOs in the FO tree or areas in the area tree.

The XSL-FO 2.0 Requirements document includes, among others, requirements for: feedback from the pagination stage; including information from formatting time; and outputting the result of an expression back into the area tree. However, the XML Print and Page Layout Working Group (as the XSL-FO subgroup became) never got to the point of working out how any of those would be expressed.

More recently, the Print and Page Layout Community Group has been collecting examples where feedback from the formatter is useful – or essential – for a satisfactory result. Thanks to Arved Sandtrom we also have proof-of-concept for running a XSL formatter from a XSLT extension function to get an area tree, so an XSLT stylesheet can now make decisions about what to put in the result based on the trial formatted size of areas, but as it’s only a proof-of-concept, it doesn’t aim as high as getting feedback from or modifying in-situ the area tree for the final, formatted document.

Once people have tried a few things with getting feedback from the XSL formatter and start asking their vendors for the same or better, they’ll also be wanting an interoperable way to express what to do with that feedback. For simple feedback of static area trees, which is all that is possible with the current proof-of-concept, the most interoperability that you could manage would be a common representation of area trees (with flexibility for vendor extensions) and, possibly, a library of XSLT functions to make it easier to navigate the area trees, but for “live” feedback, something more would be required.

The following template from the “Knight’s Tour” sample Saxon-CE application is the event handler for when the user clicks the ‘Reset’ button. It simply writes a no-break space to each square on the Knight’s chess board

<xsl:template match="button[@id='reset']" mode="ixsl:onclick">
  <xsl:for-each select="//div[starts-with(@id, 'square')]">
     <xsl:result-document href="#{@id}" method="replace-content">
       <xsl:text>&#xa0;</xsl:text>
     </xsl:result-document>
  </xsl:for-each>
</xsl:template>

The key feature of the event handler for the purposes of this discussion is that it’s written in plain old XSLT. The advantage of the XSLT event handler for Saxon-CE users is interactivity “without dropping down into JavaScript” (as the Saxon-CE documentation so delicately puts it), but the advantage for XSL-FO users would simply be that they don’t need to learn a new language (declarative, functional, or otherwise) to handle feedback. (And the advantage for those of us trying to define or implement feedback is that we don’t need to invent a whole new language to handle it.)

Applying the Saxon-CE approach to XSL-FO, the following illustrative FO event handler would handle a figure overflowing its available space by reducing its size to 80% of the current.

<xsl:template match="BlockArea[key('fig', @id, $src-doc)]"
              mode="ppl:overflow">
  <xsl:result-document href="#{@id}/area:external-graphic"
                       method="replace-content">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="width"
                     select="ppl:scale(area:external-graphic/@width,
                                       0.8)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:result-document>
</xsl:template>

(I invented a ppl:scale() XSLT extension function here so the new length is written back to the area tree rather than requiring that XSL formatters support an expression language in area tree trait values.)

An extra wrinkle for XSL-FO is the question of whether event handlers should be specified to (a) match on, and (b) modify the FO tree or the area tree or both. There are some existing requirements that can only be satisfied by modifying the area tree, e.g., Section 3.3, Output result of expression:

Allow users to output the result of expressions on area tree, traits, markers or text content. For example to calculate the subtotal of a certain page (as opposed to a running total that is already supported in XSL 1.1 with table markers)

On the other hand, it will often be simpler (from the user’s perspective) to modify an FO rather than all the areas that it generates, since a single FO may generate multiple areas across several columns or pages (and footnote areas), and its content may be reused in markers on multiple pages. If, for example, the response to a page sequence taking too many pages is to reduce the font size in one of the multiple flows appearing on the page, it would be at once simple to adjust the font-size property on the appropriate FOs in the FO tree and inaccurate to directly modify font sizes in the line areas in the area tree. If the XSL formatter did the work based on modified FOs, it would reflow the line areas based on their reduced font size and make the pages again and the resulting modified block areas would break across pages in different places because of the smaller font size. If the XSLT stylesheet did the work by modifying the area tree, it would have to do the same recalculating of text sizes and the same merging or splitting of line areas and of block areas, and all (probably) without the benefit of font metrics. It might work, just, in a simple case with only monospace fonts, but would still be a lot of work to do in XSLT.

Adapting the Saxon-CE event model to XSL-FO is, therefore, an interesting possible solution to handling feedback from the XSL formatter, but there are still many FO-specific details that would have to be worked out.