我们有一个基于Java的系统,它从数据库中读取数据,将单个数据字段与预设的XSL-FO
标记合并,并将结果转换为PDF
Apache FOP
。
以XSL-FO
格式显示如下:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE Html [
<!ENTITY nbsp " ">
<!-- all other entities -->
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" font-family="..." font-size="...">
<fo:layout-master-set>
<fo:simple-page-master master-name="Letter Page" page-width="8.500in" page-height="11.000in">
<!-- appropriate settings -->
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="Letter Page">
<!-- some static content -->
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:table ...>
<fo:table-column ... />
<fo:table-body>
<fo:table-row>
<fo:table-cell ...>
<fo:block text-align="...">
<fo:inline font-size="..." font-weight="...">
<!-- Header / Title -->
</fo:inline>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
<fo:block>
<fo:table ...>
<fo:table-column ... />
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block ...>
<!-- Field A -->
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<!-- Other fields in a very similar fashion as the above "Field A" -->
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
现在我正在寻找一种允许某些字段包含静态 HTML格式内容的方法。此内容将由我们支持HTML的编辑器生成(类似于CLEditor
,CKEditor
等)或从外部粘贴。
我的计划是遵循食谱from this JavaWorld article:
JTidy
将HTML格式的字符串转换为正确的XHTML 我有这样的代码的裸骨版本,并得到以下错误:
(错误的位置未知)org.apache.fop1.fo.ValidationException: &#34; {http://www.w3.org/1999/XSL/Format}表体&#34;不是一个有效的孩子 &#34; fo:block&#34;! (没有上下文信息)
我的问题:
<fo:block>
可以作为通用容器,其他对象(包括表格)嵌套在里面吗?如果某人已经&#34; 完成了&#34;,请分享您的体验。
答案 0 :(得分:4)
如果您使用XXT调试器,例如oXygen或XML Spy,那么您可以逐步完成转换。使用oXygen - 不确定XML Spy或其他编辑器 - 如果单击调试器输出中的标记,oXygen将突出显示源和生成该节点的样式表的标记。
获得FO后, focheck 框架(https://github.com/AntennaHouse/focheck)对当前可用的FO进行了最完整的验证。
fo:block
可以包含表格等。在XSL 1.1规范中,每个FO的定义都包含一个&#39;内容&#39;列出其允许内容的子部分。例如,见http://www.w3.org/TR/xsl11/#fo_block。 &#39;参数实体的定义&#39;内容模型中的http://www.w3.org/TR/xsl11/#d0e6532,但有些FO在其定义文本中有其他限制。您可以将具有非FO标记的<!-- Field A -->
替换为提供足够信息以引入要插入的字段的非FO标记,而不是将从您的JTidy编辑的HTML转换为静态FO。然后,您可以创建一个XSLT样式表,通过对FO部分进行标识转换,将模板+引用文档转换为直接FO,如@kevin-brown的答案,并使用引用标记中的信息构建与document()
函数(http://www.w3.org/TR/xslt#document)一起使用的URI,用于查找要插入的标记。
如果字段内容的FO位于磁盘上,则使用document()
非常简单。如果不是,那么你必须做一些事情,比如重写XSLT处理器使用的URIResolver,这样,它不是在磁盘上查找,而是检索内容。您甚至可以将JTidy作为URIResolver检索HTML的一部分进行。您也可以转换到FO&#39; inside&#39; URIResolver或者@ kevin-brown建议,将它作为一个单独的模式。如果转换是在URIResolver检索FO之前或期间完成的,那么主要的&#39;模板的转换+对FO的引用只需要提取FO子文档的正确部分,例如, document('constructed-URI')/fo:root/fo:page-sequence/*
。但是,如果您要从Antenna House修改样式表,那么无论如何您应该能够修改它以不产生外部fo:root
等。
我多年前做过类似的事情,为基于XSLT的服务器覆盖了libxslt XSLT处理器的URI解析器:内部XSLT处理器连续运行的上下文被保存为特殊URI的文档,并且不是必需的写入文件系统。
相反,您可以编写一个扩展函数来查找对字段的引用。例如,打印和页面布局社区组@W3C已经为多个XSLT处理器生成了扩展函数,这些处理器在XSLT转换过程中运行FO处理器,以获取格式化结果的区域树的XML。见http://www.w3.org/community/ppl/wiki/XSLTExtensions
答案 1 :(得分:3)
排除故障的最佳方法是使用验证查看器/编辑器来检查XSL FO。许多(例如oXygen)会在您打开它们时向您显示XSL FO结构中的错误,并且它们将描述该问题(就像报告的错误一样)。
在你的情况下,你显然有一个fo:table-body作为fo:block的孩子。它不可能是。 fo:table-body只有一个有效的父元素fo:table。您要么缺少fo:table标签,要么错误地在此位置插入了fo:block。
在我看来,我可能会做一些稍微不同的事情。我会将XHTML内容直接放入您想要的XSL FO中。然后我将创建一个身份转换,复制所有基于fo的内容,但使用XSL转换XHTML部分。通过这种方式,您可以在像XXygen这样的XSL编辑器中实际执行转换,并查看错误发生的位置以及确切原因。像任何其他德国人一样。
注意:您可能也希望查看其他XSL,特别是如果您的HTML可能有任何样式=&#34;&#34; CSS属性。如果是这种情况,它不是简单的HTML,那么你将需要一个更好的方法来处理HTML到FO的HTML。
http://www.cloudformatter.com/css2pdf基于这个完整的转换。这个通用样式表可以在这里找到:http://xep.cloudformatter.com/doc/XSL/xeponline-fo-translate-2.xsl
我是该样式表的作者。它比你提出的要多得多,但是有一个相当复杂的解析递归,用于将CSS样式转换为XSL FO属性。