问题
I have an xml document as shown below. Each repeating doc is a page in PDF file
<AFPXMLFile>
<docs>
<regList>
<region>1</region>
<secList>
<col>1</col>
<lines></lines>
</secList>
</regList>
<regList>
<region>2</region>
<secList>
<col>2</col>
<lines>
<line>IBM BELGIUM xxx</line>
<line>xxxxxx</line>
<line>xxxx</line>
</lines>
</secList>
</regList>
<regList></regList>
<regList></regList>
</docs>
<docs></docs>
</AFPXMLFile>
My XSL is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="fo">
<xsl:template match="AFPXMLFile">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master page-width="21cm" page-height="29.7cm" margin-top="1.27cm" margin-bottom="1.27cm" margin-left="1.75cm" master-name="A4">
<fo:region-body margin-top="1mm" margin-bottom="1mm"/>
<fo:region-before extent="0mm"/>
<fo:region-after extent="0mm"/>
<fo:region-start writing-mode="tb-rl" precedence="true" extent="10mm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4" font-family="sans-serif">
<xsl:for-each select="docs">
<xsl:for-each select="./regList">
<xsl:choose>
<xsl:when test="region = 1">
<fo:static-content flow-name="xsl-region-before">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="purple">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
<xsl:when test="region = 2">
<fo:static-content flow-name="xsl-region-start">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
<xsl:when test="region = 3">
<fo:static-content flow-name="xsl-region-body">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="blue">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
<xsl:when test="region = 4">
<fo:flow flow-name="xsl-region-after">
<xsl:for-each select="./secList">
<xsl:for-each select="./lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="orange">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</fo:flow>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
When I run the transformation I get the following error:
org.apache.fop.fo.ValidationException: For "fo:page-sequence", "fo:static-content" must be declared before "fo:flow"! (No context info available)
This I suspect because it is repeating the static content region for each page. So I believe I need to change the simple-page-master:master-name for every page I need help with that.
回答1:
According to the XSL-FO recommendation, the contents of 'fo:page-sequence' is:
(title?,folio-prefix?,folio-suffix?,static-content*,flow+)
which means that all the fo:static-content
elements must be before the fo:flow
elements.
Your stylesheet dynamically creates either fo:static-content
(if region
is 1, 2 or 3) or fo:flow
(if region
is 4). From the reduced input file in your question it is not possible to see whether the regList
elements are alway correctly sorted, so that they produce a valid output when sequentially processed.
Moreover, as each docs
element represents a different document with different headers/footers, you have to create distinct fo:page-sequence
s instead of a single one (otherwise you get too many static contents and flows for a single page sequence):
<xsl:for-each select="docs">
<fo:page-sequence master-reference="A4" font-family="sans-serif">
<xsl:for-each select="./regList">
....
</xsl:for-each>
</fo:page-sequence>
</xsl:for-each>
Moreover, there is a strange thing in the stylesheet: you map an fo:static-content
to the xsl-region-body
region, and the fo:flow
to the xsl-region-after
region, which is quite unusual. If the "real" content for the body region is the one with region
= 3, you must process region
1, 2 and 4 first, and then region 3:
<xsl:for-each select="docs">
<fo:page-sequence master-reference="A4" font-family="sans-serif">
<!-- create static contents -->
<xsl:apply-templates select="./regList[region != '3']"/>
<!-- create flow -->
<xsl:apply-templates select="./regList[region = '3']"/>
</fo:page-sequence>
</xsl:for-each>
with an additional template to match reglist
:
<xsl:template match="regList">
<xsl:choose>
<xsl:when test="region = '1'">
<fo:static-content flow-name="xsl-region-before">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="purple">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
<xsl:when test="region = '2'">
<fo:static-content flow-name="xsl-region-start">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
<xsl:when test="region = '3'">
<fo:flow flow-name="xsl-region-body">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="blue">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:flow>
</xsl:when>
<xsl:when test="region = '4'">
<fo:static-content flow-name="xsl-region-after">
<xsl:for-each select="./secList">
<xsl:for-each select="./lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="orange">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:when>
</xsl:choose>
</xsl:template>
or several, smaller templates:
<xsl:template match="reglist[region = '1']">
<fo:static-content flow-name="xsl-region-before">
<xsl:for-each select="./secList/lines">
<xsl:for-each select="node()">
<fo:block font-size="8pt" color="purple">
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:for-each>
</fo:static-content>
</xsl:template>
<xsl:template match="reglist[region = '2']">
...
</xsl:template>
...
来源:https://stackoverflow.com/questions/45641048/need-to-dynamically-change-the-simple-page-masters-master-name