So there's an XML format which can encapsulate a whole Word document in a single file without the need for a zip of seperate files, and "rels" files?
Sounds interesting.
But XSLT is just such a pain! It shoehorns procedural processing into XML style declarations. Everything is a pain! I wrote a transformation to transform from our page description XML into XSL-FO and it was horrible. Just horrible. And when is a string that you use as an attribute value of one of your XSLT commands a selector or the result of a selector, or the string, or a function call, or the result of the function call?
What I have done is implement a Java class which encapsulates a lot of the powerful concepts of XSL. So it parses an input document into a DOM tree, and then allows you do select and process elements of it using XPath selectors.
You can also create your output document based on calls which mirror XSLT's element and attribute creation tags.
It's based on a stack at the top of which is your "current" input node. And there are built in functions which interrogate and select from the current node.
So I took my XSLT code to create FO from this
- Code: Select all
<xsl:template match="page">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="document">
<xsl:attribute name="margin-top"><xsl:value-of select="@margin-top"/></xsl:attribute>
<xsl:attribute name="margin-right"><xsl:value-of select="@margin-right"/></xsl:attribute>
<xsl:attribute name="margin-bottom"><xsl:value-of select="@margin-bottom"/></xsl:attribute>
<xsl:attribute name="margin-left"><xsl:value-of select="@margin-left"/></xsl:attribute>
<xsl:attribute name="page-width"><xsl:value-of select="@width"/></xsl:attribute>
<xsl:attribute name="page-height"><xsl:value-of select="@height"/></xsl:attribute>
<fo:region-body>
<xsl:attribute name="margin-top"><xsl:value-of select="header/@height"/></xsl:attribute>
<xsl:attribute name="margin-bottom"><xsl:value-of select="footer/@height"/></xsl:attribute>
</fo:region-body>
<fo:region-before region-name="header">
<xsl:attribute name="extent"><xsl:value-of select="header/@height"/></xsl:attribute>
</fo:region-before>
<fo:region-after region-name="footer">
<xsl:attribute name="extent"><xsl:value-of select="footer/@height"/></xsl:attribute>
</fo:region-after>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="document">
<!-- Subset of page attributes applied to page-sequence -->
<xsl:call-template name="copy-attributes">
<xsl:with-param name="attributes" select="@font|@font-family|@font-size|@font-weight|@colour|@color"/>
</xsl:call-template>
<!-- Only process header if there are header children, or a background image. -->
<xsl:if test="count(header/*) + count(background-image) != 0">
<xsl:apply-templates select="header[1]" />
</xsl:if>
<!-- Only process footer if there are footer children. -->
<xsl:if test="count(footer/*) != 0">
<xsl:apply-templates select="footer[1]" />
</xsl:if>
<!-- Process the body -->
<xsl:apply-templates select="body" />
</fo:page-sequence>
</fo:root>
</xsl:template>
to this
- Code: Select all
@Template(match="page")
public void transformPage() throws Exception {
element("fo:root");
xmlns("fo", "http://www.w3.org/1999/XSL/Format");
element("fo:layout-master-set");
element("fo:simple-page-master", "master-name", "document");
attribute("margin-top", select("@margin-top"));
attribute("margin-right", select("@margin-right"));
attribute("margin-bottom", select("@margin-bottom"));
attribute("margin-left", select("@margin-left"));
attribute("page-width", select("@width"));
attribute("page-height", select("@height"));
element("fo:region-body");
attribute("margin-top", select("header/@height"));
attribute("margin-bottom", select("footer/@height"));
closeElement("fo:region-body");
element("fo:region-before", "region-name", "header");
attribute("extent", select("header/@height"));
closeElement("fo:region-before");
element("fo:region-after", "region-name", "footer");
attribute("extent", select("footer/@height"));
closeElement("fo:region-after");
closeElement("fo:simple-page-master");
closeElement("fo:layout-master-set");
element("fo:page-sequence", "master-reference", "document");
// Subset of page attributes applied to page-sequence
copyAttributes(select("@font|@font-family|@font-size|@font-weight|@colour|@color"));
// Only process header if there are header children, or a background image. -->
if (count("header/*") + count("background-image") != 0) {
applyTemplates("header[1]");
}
// Only process footer if there are footer children. -->
if (count("footer/*") != 0) {
applyTemplates("footer[1]");
}
// Process the body -->
applyTemplates("body");
closeElement("fo:page-sequence");
closeElement("fo:root");
}
You can see the mapping. But I'm in code! Real code in which I can easily DO STUFF!
The selector which is automatically attached to the template is attached by a Java annotation, so to kick off processing, you just call
- Code: Select all
applyTemplates();
And it applies matching methods.