我使用xsl样式表 ReportXHTML.xsl 将具有2个表的XML文件 ReportXHTML.xml 转换为xhtml。下一步,我构建了可比较的XSL-FO文件 ReportFO.xsl ,将其与修改后的xml文件 ReportFO.xml 和Apache FOP一起使用以获取PDF文件,但我的Java应用程序 FopReport.java 因此 ValidationException
而失败“ fo:table-row”缺少子元素。所需内容模型: (table-cell +)
寻找解决方案,我阅读了XSL-Fo规范,并通过删除名为table-rows的xsl模板中的xsl声明 for-each 来修改XSL-FO文件。我得到了PDF ReportFO.pdf 文件。
这表明名为 table-head 的xsl模板中的每个xsl语句均有效。名为 table-rows 的xsl模板与此类似,但失败了。那是我的问题。在XSL-FO文件中要修改什么?感谢您的帮助。
ReportXHTML.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="ReportXHTML.xsl" ?>
<report>
<table>
<tableRow>
<tableHead>Name</tableHead>
<tableHead>Street</tableHead>
<tableHead>City</tableHead>
</tableRow>
<tableRow>
<entry>Torsten Horn</entry>
<entry>Hauptsr. 44</entry>
<entry>Aachen</entry>
</tableRow>
<tableRow>
<entry>Heinz Hinz</entry>
<entry>Bahnhofstr. 22</entry>
<entry>Hamburg</entry>
</tableRow>
<tableRow>
<entry>Karl Kunz</entry>
<entry>Königstr. 1</entry>
<entry>Köln</entry>
</tableRow>
</table>
<table>
<tableRow>
<tableHead>Name</tableHead>
<tableHead>City</tableHead>
</tableRow>
<tableRow>
<entry>Torsten Horn</entry>
<entry>Aachen</entry>
</tableRow>
<tableRow>
<entry>Heinz Hinz</entry>
<entry>Hamburg</entry>
</tableRow>
<tableRow>
<entry>Karl Kunz</entry>
<entry>Köln</entry>
</tableRow>
</table>
</report>
样式表ReportXHTML.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<html>
<head>
<title>Report</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
<xsl:template match="table">
<p>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<xsl:for-each select="tableRow/tableHead">
<th><xsl:apply-templates/></th>
</xsl:for-each>
</tr>
<xsl:for-each select="tableRow">
<tr>
<xsl:for-each select="entry">
<td><xsl:apply-templates/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</p>
</xsl:template>
</xsl:stylesheet>
FireFox的结果: image of result
样式表ReportFO.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xs:stylesheet version="1.0"
xmlns:xs="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<!-- XLS/ FO Specification see: https://www.w3.org/TR/xsl11/ -->
<!-- Attribute-Sets -->
<xs:attribute-set name="cell-style">
<xs:attribute name="border-width">0.5pt</xs:attribute>
<xs:attribute name="border-style">solid</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="block-style">
<xs:attribute name="font-size"> 10pt</xs:attribute>
<xs:attribute name="line-height">15pt</xs:attribute>
<xs:attribute name="start-indent">1mm</xs:attribute>
<xs:attribute name="end-indent"> 1mm</xs:attribute>
</xs:attribute-set>
<!-- Page Layout -->
<xs:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="DIN-A4"
page-height="29.7cm" page-width="21cm"
margin-top="2cm" margin-bottom="1.5cm"
margin-left="2.5cm" margin-right="1.0cm">
<fo:region-body
margin-top="1.5cm" margin-bottom="1.0cm"
margin-left="0.0cm" margin-right="0.0cm"/>
<fo:region-before region-name="header" extent="1.3cm"/>
<fo:region-after region-name="footer" extent="1.0cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="DIN-A4">
<fo:static-content flow-name="header">
<fo:block font-size="14pt" font-family="Helvetica" font-weight="bold" text-align="left">
Report
</fo:block>
<fo:block text-align-last="justify"><fo:leader leader-pattern="rule" rule-thickness="0.5" />
</fo:block>
</fo:static-content>
<fo:static-content flow-name="footer">
<fo:block text-align-last="justify"><fo:leader leader-pattern="rule" rule-thickness="0.5" />
</fo:block>
<fo:block font-size="10pt" text-align="center" >
Page <fo:page-number/> of <fo:page-number-citation ref-id="LastPage"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xs:apply-templates/>
<fo:block id="LastPage"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xs:template>
<!-- Table-Head -->
<xs:template name="table-head">
<fo:table-row>
<xs:for-each select="tableRow/tableHead">
<fo:table-cell xs:use-attribute-sets="cell-style">
<fo:block xs:use-attribute-sets="block-style" text-align="center">
<xs:apply-templates/>
</fo:block>
</fo:table-cell>
</xs:for-each>
</fo:table-row>
</xs:template>
<!-- Table-Rows -->
<xs:template name="table-rows">
<fo:table-row>
<xs:for-each select="tableRow/entry">
<fo:table-cell xs:use-attribute-sets="cell-style">
<fo:block xs:use-attribute-sets="block-style">
<xs:apply-templates/>
</fo:block>
</fo:table-cell>
</xs:for-each>
</fo:table-row>
</xs:template>
<!-- Table -->
<xs:template match="report/table">
<fo:block><fo:leader /></fo:block>
<fo:table border-style="solid" table-layout="fixed" width="100%">
<fo:table-header>
<xs:call-template name="table-head"/>
</fo:table-header>
<fo:table-body>
<xs:for-each select="tableRow">
<xs:call-template name="table-rows"/>
</xs:for-each>
</fo:table-body>
</fo:table>
</xs:template>
</xs:stylesheet>
修改后的xml文件ReportFO.xml
<?xml version="1.0" encoding="UTF-8"?>
<report>
<table>
<tableRow>
<tableHead>Name</tableHead>
etc .....
FopReport.java
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.*;
import org.apache.*;
// compile by: javac -classpath ".:lib/fop.jar:lib/xmlgraphics-commons-2.3.jar" FopReport.java
// run by:
// java -classpath ".:lib/fop.jar:lib/xmlgraphics-commons-2.3.jar:lib/commons-logging-1.0.4.jar:lib/avalon-framework-api-4.3.1.jar:lib/avalon-framework-impl-4.3.1.jar:lib/commons-io-1.3.1.jar:lib/batik-all-1.10.jar" FopReport ReportFO.xsl ReportFO.xml ReportFO.pdf
// see : https://xmlgraphics.apache.org/fop/2.3/embedding.html
public class FopReport
{
public static void main( String[] args ) throws Exception
{
if( args.length != 3 ) {
System.out.println( "Enter XSL- and XML-Inputfile, PDF-Outputfile." );
return;
}
FopReport.xmlToPdfPerXsl( args[0], args[1], args[2] );
System.out.println( args[0] + " + " + args[1] + " --> " + args[2] );
}
public static void xmlToPdfPerXsl( String inputXSL, String inputXML, String outputPDF ) throws Exception
{
// Step 1: Construct a FopFactory by specifying a reference to the configuration file
// (reuse if you plan to render multiple documents!)
FopFactory fopFactory = FopFactory.newInstance(new File("fop.xconf"));
// Step 2: Set up output stream
OutputStream pdf = new FileOutputStream( outputPDF );
// Step 3: Construct fop with desired output format
// Fop fop = FopFactory.newFop( MimeConstants.MIME_PDF, pdf );
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, pdf);
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
Source xml = new StreamSource( inputXML );
Source xsl = new StreamSource( inputXSL );
// Resulting SAX events (the generated FO) must be piped through to FOP
Result sax = new SAXResult( fop.getDefaultHandler() );
// Step 4: Setup JAXP using identity transformer
// Transformer transformer = TransformerFactory.newInstance().newTransformer( xsl );
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer( xsl ); // identity transformer
// Step 6: Start XSLT transformation and FOP processing
transformer.transform( xml, sax );
}
}
验证异常
Nov. 11, 2018 7:34:05 NACHM. org.apache.fop.apps.FopConfParser configure
INFORMATION: Default page-height set to: 11in
Nov. 11, 2018 7:34:05 NACHM. org.apache.fop.apps.FopConfParser configure
INFORMATION: Default page-width set to: 8.26in
ERROR: '"fo:table-row" is missing child elements. Required content model: (table-cell+) (No context info available)'
Exception in thread "main" javax.xml.transform.TransformerException: org.apache.fop.fo.ValidationException: "fo:table-row" is missing child elements. Required content model: (table- cell+) (Keine Kontextinformationen verfügbar)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:786)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:370)
at FopReport.xmlToPdfPerXsl(FopReport.java:52)
at FopReport.main(FopReport.java:22)
Caused by: org.apache.fop.fo.ValidationException: "fo:table-row" is missing child elements. Required content model: (table-cell+) (Keine Kontextinformationen verfügbar)
at org.apache.fop.events.ValidationExceptionFactory.createException(ValidationExceptionFactory.java:38)
at org.apache.fop.events.EventExceptionManager.throwException(EventExceptionManager.java:58)
at org.apache.fop.events.DefaultEventBroadcaster$1.invoke(DefaultEventBroadcaster.java:173)
at com.sun.proxy.$Proxy2.missingChildElement(Unknown Source)
at org.apache.fop.fo.FONode.missingChildElementError(FONode.java:588)
at org.apache.fop.fo.flow.table.TableRow.finalizeNode(TableRow.java:115)
at org.apache.fop.fo.FONode.endOfNode(FONode.java:330)
at org.apache.fop.fo.flow.table.TableRow.endOfNode(TableRow.java:108)
at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:360)
at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:190)
at java.xml/com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler.endElement(ToXMLSAXHandler.java:263)
at java.xml/com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler.endElement(ToXMLSAXHandler.java:557)
at jdk.translet/die.verwandlung.ReportFO.table$dash$rows()
at jdk.translet/die.verwandlung.ReportFO.template$dot$3()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.template$dot$0()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.transform()
at java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:624)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:776)
... 3 more
---------
org.apache.fop.fo.ValidationException: "fo:table-row" is missing child elements. Required content model: (table-cell+) (Keine Kontextinformationen verfügbar)
at org.apache.fop.events.ValidationExceptionFactory.createException(ValidationExceptionFactory.java:38)
at org.apache.fop.events.EventExceptionManager.throwException(EventExceptionManager.java:58)
at org.apache.fop.events.DefaultEventBroadcaster$1.invoke(DefaultEventBroadcaster.java:173)
at com.sun.proxy.$Proxy2.missingChildElement(Unknown Source)
at org.apache.fop.fo.FONode.missingChildElementError(FONode.java:588)
at org.apache.fop.fo.flow.table.TableRow.finalizeNode(TableRow.java:115)
at org.apache.fop.fo.FONode.endOfNode(FONode.java:330)
at org.apache.fop.fo.flow.table.TableRow.endOfNode(TableRow.java:108)
at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:360)
at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:190)
at java.xml/com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler.endElement(ToXMLSAXHandler.java:263)
at java.xml/com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler.endElement(ToXMLSAXHandler.java:557)
at jdk.translet/die.verwandlung.ReportFO.table$dash$rows()
at jdk.translet/die.verwandlung.ReportFO.template$dot$3()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.template$dot$0()
at jdk.translet/die.verwandlung.ReportFO.applyTemplates()
at jdk.translet/die.verwandlung.ReportFO.transform()
at java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:624)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:776)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:370)
at FopReport.xmlToPdfPerXsl(FopReport.java:52)
at FopReport.main(FopReport.java:22)
文件ReportFO.pdf image of ReportFO.pdf
答案 0 :(得分:0)
在这里,xs:for-each
依次更改每个tableRow/entry
的上下文,并调用带有当前tableRow
作为上下文项的'table-rows'模板:
<xs:for-each select="tableRow">
<xs:call-template name="table-rows"/>
</xs:for-each>
在这里,xs:for-each
正在将上下文更改为上下文项的每个entry
子级的每个tableRow
子级:
<!-- Table-Rows -->
<xs:template name="table-rows">
<fo:table-row>
<xs:for-each select="tableRow/entry">
<fo:table-cell xs:use-attribute-sets="cell-style">
<fo:block xs:use-attribute-sets="block-style">
<xs:apply-templates/>
</fo:block>
</fo:table-cell>
</xs:for-each>
当上下文为tableRow
时,没有tableRow/entry
可供选择。
快速的解决方案是删除tableRow
中的tableRow/entry
。
我建议,较长期的解决方案是对xs:apply-templates
做更多的事,而对xs:for-each
做更少的事。如果您使用过xs:apply-templates
,那么XSLT处理器将每次都选择子元素,然后找到最匹配的xs:template
用于每个元素。诸如此类(未经测试):
<xs:template match="table">
<fo:table>
<fo:table-header>
<xs:apply-templates select="tableRow[tableHead]" />
</fo:table-header>
<fo:table-body>
<xs:apply-templates select="tableRow[entry]" />
</fo:table-body>
</fo:table>
</xs:template>
<xs:template match="tableRow">
<fo:table-row>
<xs:apply-templates />
</fo:table-row>
</xs:template>
<xs:template match="tableHead">
<fo:table-cell xs:use-attribute-sets="cell-style">
<fo:block xs:use-attribute-sets="block-style" text-align="center">
<xs:apply-templates/>
</fo:block>
</fo:table-cell>
</xs:template>
<xs:template match="entry">
<fo:table-cell xs:use-attribute-sets="cell-style">
<fo:block xs:use-attribute-sets="block-style">
<xs:apply-templates/>
</fo:block>
</fo:table-cell>
</xs:template>